django-bulk-hooks 0.2.16__py3-none-any.whl → 0.2.17__py3-none-any.whl
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.
- django_bulk_hooks/__init__.py +20 -24
- django_bulk_hooks/changeset.py +1 -1
- django_bulk_hooks/conditions.py +8 -12
- django_bulk_hooks/decorators.py +16 -18
- django_bulk_hooks/dispatcher.py +9 -10
- django_bulk_hooks/factory.py +36 -38
- django_bulk_hooks/handler.py +5 -6
- django_bulk_hooks/helpers.py +4 -3
- django_bulk_hooks/models.py +12 -13
- django_bulk_hooks/operations/__init__.py +5 -5
- django_bulk_hooks/operations/analyzer.py +14 -14
- django_bulk_hooks/operations/bulk_executor.py +79 -71
- django_bulk_hooks/operations/coordinator.py +61 -61
- django_bulk_hooks/operations/mti_handler.py +67 -65
- django_bulk_hooks/operations/mti_plans.py +17 -16
- django_bulk_hooks/operations/record_classifier.py +22 -21
- django_bulk_hooks/queryset.py +5 -3
- django_bulk_hooks/registry.py +40 -45
- {django_bulk_hooks-0.2.16.dist-info → django_bulk_hooks-0.2.17.dist-info}/METADATA +1 -1
- django_bulk_hooks-0.2.17.dist-info/RECORD +26 -0
- django_bulk_hooks-0.2.16.dist-info/RECORD +0 -26
- {django_bulk_hooks-0.2.16.dist-info → django_bulk_hooks-0.2.17.dist-info}/LICENSE +0 -0
- {django_bulk_hooks-0.2.16.dist-info → django_bulk_hooks-0.2.17.dist-info}/WHEEL +0 -0
|
@@ -5,8 +5,9 @@ These are pure data structures returned by MTIHandler to be executed by BulkExec
|
|
|
5
5
|
This separates planning (logic) from execution (database operations).
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from dataclasses import dataclass
|
|
9
|
-
from
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from dataclasses import field
|
|
10
|
+
from typing import Any
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@dataclass
|
|
@@ -23,11 +24,11 @@ class ParentLevel:
|
|
|
23
24
|
update_fields: Fields to update on conflict (if update_conflicts=True)
|
|
24
25
|
"""
|
|
25
26
|
model_class: Any
|
|
26
|
-
objects:
|
|
27
|
-
original_object_map:
|
|
27
|
+
objects: list[Any]
|
|
28
|
+
original_object_map: dict[int, int] = field(default_factory=dict)
|
|
28
29
|
update_conflicts: bool = False
|
|
29
|
-
unique_fields:
|
|
30
|
-
update_fields:
|
|
30
|
+
unique_fields: list[str] = field(default_factory=list)
|
|
31
|
+
update_fields: list[str] = field(default_factory=list)
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
@dataclass
|
|
@@ -50,16 +51,16 @@ class MTICreatePlan:
|
|
|
50
51
|
unique_fields: Fields used for conflict detection
|
|
51
52
|
update_fields: Fields to update on conflict
|
|
52
53
|
"""
|
|
53
|
-
inheritance_chain:
|
|
54
|
-
parent_levels:
|
|
55
|
-
child_objects:
|
|
54
|
+
inheritance_chain: list[Any]
|
|
55
|
+
parent_levels: list[ParentLevel]
|
|
56
|
+
child_objects: list[Any]
|
|
56
57
|
child_model: Any
|
|
57
|
-
original_objects:
|
|
58
|
+
original_objects: list[Any]
|
|
58
59
|
batch_size: int = None
|
|
59
60
|
existing_record_ids: set = field(default_factory=set)
|
|
60
61
|
update_conflicts: bool = False
|
|
61
|
-
unique_fields:
|
|
62
|
-
update_fields:
|
|
62
|
+
unique_fields: list[str] = field(default_factory=list)
|
|
63
|
+
update_fields: list[str] = field(default_factory=list)
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
@dataclass
|
|
@@ -73,7 +74,7 @@ class ModelFieldGroup:
|
|
|
73
74
|
filter_field: Field to use for filtering (e.g., 'pk' or parent link attname)
|
|
74
75
|
"""
|
|
75
76
|
model_class: Any
|
|
76
|
-
fields:
|
|
77
|
+
fields: list[str]
|
|
77
78
|
filter_field: str = "pk"
|
|
78
79
|
|
|
79
80
|
|
|
@@ -88,8 +89,8 @@ class MTIUpdatePlan:
|
|
|
88
89
|
objects: Objects to update
|
|
89
90
|
batch_size: Batch size for operations
|
|
90
91
|
"""
|
|
91
|
-
inheritance_chain:
|
|
92
|
-
field_groups:
|
|
93
|
-
objects:
|
|
92
|
+
inheritance_chain: list[Any]
|
|
93
|
+
field_groups: list[ModelFieldGroup]
|
|
94
|
+
objects: list[Any]
|
|
94
95
|
batch_size: int = None
|
|
95
96
|
|
|
@@ -8,6 +8,7 @@ Separates data access concerns from business logic.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
|
+
|
|
11
12
|
from django.db.models import Q
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
@@ -48,11 +49,11 @@ class RecordClassifier:
|
|
|
48
49
|
"""
|
|
49
50
|
if not unique_fields or not objs:
|
|
50
51
|
return set(), {}
|
|
51
|
-
|
|
52
|
+
|
|
52
53
|
# Build a query to find existing records
|
|
53
54
|
queries = []
|
|
54
55
|
obj_to_unique_values = {}
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
for obj in objs:
|
|
57
58
|
# Build lookup dict for this object's unique fields
|
|
58
59
|
lookup = {}
|
|
@@ -67,36 +68,36 @@ class RecordClassifier:
|
|
|
67
68
|
if lookup:
|
|
68
69
|
queries.append(Q(**lookup))
|
|
69
70
|
obj_to_unique_values[id(obj)] = tuple(lookup.values())
|
|
70
|
-
|
|
71
|
+
|
|
71
72
|
if not queries:
|
|
72
73
|
return set(), {}
|
|
73
|
-
|
|
74
|
+
|
|
74
75
|
# Query for existing records
|
|
75
76
|
combined_query = queries[0]
|
|
76
77
|
for q in queries[1:]:
|
|
77
78
|
combined_query |= q
|
|
78
|
-
|
|
79
|
+
|
|
79
80
|
existing_records = list(
|
|
80
|
-
self.model_cls.objects.filter(combined_query).values(
|
|
81
|
+
self.model_cls.objects.filter(combined_query).values("pk", *unique_fields),
|
|
81
82
|
)
|
|
82
|
-
|
|
83
|
+
|
|
83
84
|
# Map existing records back to original objects
|
|
84
85
|
existing_record_ids = set()
|
|
85
86
|
existing_pks_map = {}
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
for record in existing_records:
|
|
88
89
|
record_values = tuple(record[field] for field in unique_fields)
|
|
89
90
|
# Find which object(s) match these values
|
|
90
91
|
for obj_id, obj_values in obj_to_unique_values.items():
|
|
91
92
|
if obj_values == record_values:
|
|
92
93
|
existing_record_ids.add(obj_id)
|
|
93
|
-
existing_pks_map[obj_id] = record[
|
|
94
|
-
|
|
94
|
+
existing_pks_map[obj_id] = record["pk"]
|
|
95
|
+
|
|
95
96
|
logger.info(
|
|
96
97
|
f"Classified {len(existing_record_ids)} existing and "
|
|
97
|
-
f"{len(objs) - len(existing_record_ids)} new records for upsert"
|
|
98
|
+
f"{len(objs) - len(existing_record_ids)} new records for upsert",
|
|
98
99
|
)
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
return existing_record_ids, existing_pks_map
|
|
101
102
|
|
|
102
103
|
def fetch_by_pks(self, pks, select_related=None, prefetch_related=None):
|
|
@@ -113,15 +114,15 @@ class RecordClassifier:
|
|
|
113
114
|
"""
|
|
114
115
|
if not pks:
|
|
115
116
|
return {}
|
|
116
|
-
|
|
117
|
+
|
|
117
118
|
queryset = self.model_cls._base_manager.filter(pk__in=pks)
|
|
118
|
-
|
|
119
|
+
|
|
119
120
|
if select_related:
|
|
120
121
|
queryset = queryset.select_related(*select_related)
|
|
121
|
-
|
|
122
|
+
|
|
122
123
|
if prefetch_related:
|
|
123
124
|
queryset = queryset.prefetch_related(*prefetch_related)
|
|
124
|
-
|
|
125
|
+
|
|
125
126
|
return {obj.pk: obj for obj in queryset}
|
|
126
127
|
|
|
127
128
|
def fetch_by_unique_constraint(self, field_values_map):
|
|
@@ -141,7 +142,7 @@ class RecordClassifier:
|
|
|
141
142
|
except self.model_cls.MultipleObjectsReturned:
|
|
142
143
|
logger.warning(
|
|
143
144
|
f"Multiple {self.model_cls.__name__} records found for "
|
|
144
|
-
f"unique constraint {field_values_map}"
|
|
145
|
+
f"unique constraint {field_values_map}",
|
|
145
146
|
)
|
|
146
147
|
return self.model_cls.objects.filter(**field_values_map).first()
|
|
147
148
|
|
|
@@ -157,11 +158,11 @@ class RecordClassifier:
|
|
|
157
158
|
"""
|
|
158
159
|
if not pks:
|
|
159
160
|
return set()
|
|
160
|
-
|
|
161
|
+
|
|
161
162
|
existing_pks = self.model_cls.objects.filter(
|
|
162
|
-
pk__in=pks
|
|
163
|
-
).values_list(
|
|
164
|
-
|
|
163
|
+
pk__in=pks,
|
|
164
|
+
).values_list("pk", flat=True)
|
|
165
|
+
|
|
165
166
|
return set(existing_pks)
|
|
166
167
|
|
|
167
168
|
def count_by_unique_fields(self, objs, unique_fields):
|
django_bulk_hooks/queryset.py
CHANGED
|
@@ -7,7 +7,9 @@ complex coordination required for bulk operations with hooks.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
from django.db import models
|
|
12
|
+
from django.db import transaction
|
|
11
13
|
|
|
12
14
|
logger = logging.getLogger(__name__)
|
|
13
15
|
|
|
@@ -98,7 +100,7 @@ class HookQuerySet(models.QuerySet):
|
|
|
98
100
|
fields = self.coordinator.analyzer.detect_changed_fields(objs)
|
|
99
101
|
if not fields:
|
|
100
102
|
logger.debug(
|
|
101
|
-
f"bulk_update: No fields changed for {len(objs)} {self.model.__name__} objects"
|
|
103
|
+
f"bulk_update: No fields changed for {len(objs)} {self.model.__name__} objects",
|
|
102
104
|
)
|
|
103
105
|
return 0
|
|
104
106
|
|
|
@@ -133,7 +135,7 @@ class HookQuerySet(models.QuerySet):
|
|
|
133
135
|
|
|
134
136
|
@transaction.atomic
|
|
135
137
|
def bulk_delete(
|
|
136
|
-
self, objs, bypass_hooks=False, bypass_validation=False, **kwargs
|
|
138
|
+
self, objs, bypass_hooks=False, bypass_validation=False, **kwargs,
|
|
137
139
|
):
|
|
138
140
|
"""
|
|
139
141
|
Delete multiple objects with hook support.
|
django_bulk_hooks/registry.py
CHANGED
|
@@ -8,14 +8,13 @@ deterministic priority ordering.
|
|
|
8
8
|
import logging
|
|
9
9
|
import threading
|
|
10
10
|
from collections.abc import Callable
|
|
11
|
-
from typing import Dict, List, Optional, Tuple, Type, Union
|
|
12
11
|
|
|
13
12
|
from django_bulk_hooks.enums import Priority
|
|
14
13
|
|
|
15
14
|
logger = logging.getLogger(__name__)
|
|
16
15
|
|
|
17
16
|
# Type alias for hook info tuple
|
|
18
|
-
HookInfo =
|
|
17
|
+
HookInfo = tuple[type, str, Callable | None, int]
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
class HookRegistry:
|
|
@@ -30,17 +29,17 @@ class HookRegistry:
|
|
|
30
29
|
|
|
31
30
|
def __init__(self):
|
|
32
31
|
"""Initialize an empty registry with thread-safe storage."""
|
|
33
|
-
self._hooks:
|
|
32
|
+
self._hooks: dict[tuple[type, str], list[HookInfo]] = {}
|
|
34
33
|
self._lock = threading.RLock()
|
|
35
34
|
|
|
36
35
|
def register(
|
|
37
36
|
self,
|
|
38
|
-
model:
|
|
37
|
+
model: type,
|
|
39
38
|
event: str,
|
|
40
|
-
handler_cls:
|
|
39
|
+
handler_cls: type,
|
|
41
40
|
method_name: str,
|
|
42
|
-
condition:
|
|
43
|
-
priority:
|
|
41
|
+
condition: Callable | None,
|
|
42
|
+
priority: int | Priority,
|
|
44
43
|
) -> None:
|
|
45
44
|
"""
|
|
46
45
|
Register a hook handler for a model and event.
|
|
@@ -64,16 +63,14 @@ class HookRegistry:
|
|
|
64
63
|
# Sort by priority (lower values first)
|
|
65
64
|
hooks.sort(key=lambda x: x[3])
|
|
66
65
|
logger.debug(
|
|
67
|
-
f"Registered {handler_cls.__name__}.{method_name} "
|
|
68
|
-
f"for {model.__name__}.{event} (priority={priority})"
|
|
66
|
+
f"Registered {handler_cls.__name__}.{method_name} for {model.__name__}.{event} (priority={priority})",
|
|
69
67
|
)
|
|
70
68
|
else:
|
|
71
69
|
logger.debug(
|
|
72
|
-
f"Hook {handler_cls.__name__}.{method_name} "
|
|
73
|
-
f"already registered for {model.__name__}.{event}"
|
|
70
|
+
f"Hook {handler_cls.__name__}.{method_name} already registered for {model.__name__}.{event}",
|
|
74
71
|
)
|
|
75
72
|
|
|
76
|
-
def get_hooks(self, model:
|
|
73
|
+
def get_hooks(self, model: type, event: str) -> list[HookInfo]:
|
|
77
74
|
"""
|
|
78
75
|
Get all hooks for a model and event.
|
|
79
76
|
|
|
@@ -97,13 +94,17 @@ class HookRegistry:
|
|
|
97
94
|
"before_create",
|
|
98
95
|
]:
|
|
99
96
|
logger.debug(
|
|
100
|
-
f"get_hooks {model.__name__}.{event} found {len(hooks)} hooks"
|
|
97
|
+
f"get_hooks {model.__name__}.{event} found {len(hooks)} hooks",
|
|
101
98
|
)
|
|
102
99
|
|
|
103
100
|
return hooks
|
|
104
101
|
|
|
105
102
|
def unregister(
|
|
106
|
-
self,
|
|
103
|
+
self,
|
|
104
|
+
model: type,
|
|
105
|
+
event: str,
|
|
106
|
+
handler_cls: type,
|
|
107
|
+
method_name: str,
|
|
107
108
|
) -> None:
|
|
108
109
|
"""
|
|
109
110
|
Unregister a specific hook handler.
|
|
@@ -124,9 +125,7 @@ class HookRegistry:
|
|
|
124
125
|
hooks = self._hooks[key]
|
|
125
126
|
# Filter out the specific hook
|
|
126
127
|
self._hooks[key] = [
|
|
127
|
-
(h_cls, m_name, cond, pri)
|
|
128
|
-
for h_cls, m_name, cond, pri in hooks
|
|
129
|
-
if not (h_cls == handler_cls and m_name == method_name)
|
|
128
|
+
(h_cls, m_name, cond, pri) for h_cls, m_name, cond, pri in hooks if not (h_cls == handler_cls and m_name == method_name)
|
|
130
129
|
]
|
|
131
130
|
|
|
132
131
|
# Clean up empty hook lists
|
|
@@ -134,8 +133,7 @@ class HookRegistry:
|
|
|
134
133
|
del self._hooks[key]
|
|
135
134
|
|
|
136
135
|
logger.debug(
|
|
137
|
-
f"Unregistered {handler_cls.__name__}.{method_name} "
|
|
138
|
-
f"for {model.__name__}.{event}"
|
|
136
|
+
f"Unregistered {handler_cls.__name__}.{method_name} for {model.__name__}.{event}",
|
|
139
137
|
)
|
|
140
138
|
|
|
141
139
|
def clear(self) -> None:
|
|
@@ -155,7 +153,7 @@ class HookRegistry:
|
|
|
155
153
|
|
|
156
154
|
logger.debug("Cleared all registered hooks")
|
|
157
155
|
|
|
158
|
-
def list_all(self) ->
|
|
156
|
+
def list_all(self) -> dict[tuple[type, str], list[HookInfo]]:
|
|
159
157
|
"""
|
|
160
158
|
Get all registered hooks for debugging.
|
|
161
159
|
|
|
@@ -166,17 +164,19 @@ class HookRegistry:
|
|
|
166
164
|
return dict(self._hooks)
|
|
167
165
|
|
|
168
166
|
@property
|
|
169
|
-
def hooks(self) ->
|
|
167
|
+
def hooks(self) -> dict[tuple[type, str], list[HookInfo]]:
|
|
170
168
|
"""
|
|
171
169
|
Expose internal hooks dictionary for testing purposes.
|
|
172
|
-
|
|
170
|
+
|
|
173
171
|
This property provides direct access to the internal hooks storage
|
|
174
172
|
to allow tests to clear the registry state between test runs.
|
|
175
173
|
"""
|
|
176
174
|
return self._hooks
|
|
177
175
|
|
|
178
176
|
def count_hooks(
|
|
179
|
-
self,
|
|
177
|
+
self,
|
|
178
|
+
model: type | None = None,
|
|
179
|
+
event: str | None = None,
|
|
180
180
|
) -> int:
|
|
181
181
|
"""
|
|
182
182
|
Count registered hooks, optionally filtered by model and/or event.
|
|
@@ -192,27 +192,19 @@ class HookRegistry:
|
|
|
192
192
|
if model is None and event is None:
|
|
193
193
|
# Count all hooks
|
|
194
194
|
return sum(len(hooks) for hooks in self._hooks.values())
|
|
195
|
-
|
|
195
|
+
if model is not None and event is not None:
|
|
196
196
|
# Count hooks for specific model and event
|
|
197
197
|
return len(self._hooks.get((model, event), []))
|
|
198
|
-
|
|
198
|
+
if model is not None:
|
|
199
199
|
# Count all hooks for a model
|
|
200
|
-
return sum(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
)
|
|
205
|
-
else: # event is not None
|
|
206
|
-
# Count all hooks for an event
|
|
207
|
-
return sum(
|
|
208
|
-
len(hooks)
|
|
209
|
-
for (_, e), hooks in self._hooks.items()
|
|
210
|
-
if e == event
|
|
211
|
-
)
|
|
200
|
+
return sum(len(hooks) for (m, _), hooks in self._hooks.items() if m == model)
|
|
201
|
+
# event is not None
|
|
202
|
+
# Count all hooks for an event
|
|
203
|
+
return sum(len(hooks) for (_, e), hooks in self._hooks.items() if e == event)
|
|
212
204
|
|
|
213
205
|
|
|
214
206
|
# Global singleton registry
|
|
215
|
-
_registry:
|
|
207
|
+
_registry: HookRegistry | None = None
|
|
216
208
|
_registry_lock = threading.Lock()
|
|
217
209
|
|
|
218
210
|
|
|
@@ -239,12 +231,12 @@ def get_registry() -> HookRegistry:
|
|
|
239
231
|
|
|
240
232
|
# Backward-compatible module-level functions
|
|
241
233
|
def register_hook(
|
|
242
|
-
model:
|
|
234
|
+
model: type,
|
|
243
235
|
event: str,
|
|
244
|
-
handler_cls:
|
|
236
|
+
handler_cls: type,
|
|
245
237
|
method_name: str,
|
|
246
|
-
condition:
|
|
247
|
-
priority:
|
|
238
|
+
condition: Callable | None,
|
|
239
|
+
priority: int | Priority,
|
|
248
240
|
) -> None:
|
|
249
241
|
"""
|
|
250
242
|
Register a hook handler (backward-compatible function).
|
|
@@ -255,7 +247,7 @@ def register_hook(
|
|
|
255
247
|
registry.register(model, event, handler_cls, method_name, condition, priority)
|
|
256
248
|
|
|
257
249
|
|
|
258
|
-
def get_hooks(model:
|
|
250
|
+
def get_hooks(model: type, event: str) -> list[HookInfo]:
|
|
259
251
|
"""
|
|
260
252
|
Get hooks for a model and event (backward-compatible function).
|
|
261
253
|
|
|
@@ -266,7 +258,10 @@ def get_hooks(model: Type, event: str) -> List[HookInfo]:
|
|
|
266
258
|
|
|
267
259
|
|
|
268
260
|
def unregister_hook(
|
|
269
|
-
model:
|
|
261
|
+
model: type,
|
|
262
|
+
event: str,
|
|
263
|
+
handler_cls: type,
|
|
264
|
+
method_name: str,
|
|
270
265
|
) -> None:
|
|
271
266
|
"""
|
|
272
267
|
Unregister a hook handler (backward-compatible function).
|
|
@@ -288,7 +283,7 @@ def clear_hooks() -> None:
|
|
|
288
283
|
registry.clear()
|
|
289
284
|
|
|
290
285
|
|
|
291
|
-
def list_all_hooks() ->
|
|
286
|
+
def list_all_hooks() -> dict[tuple[type, str], list[HookInfo]]:
|
|
292
287
|
"""
|
|
293
288
|
List all registered hooks (backward-compatible function).
|
|
294
289
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
django_bulk_hooks/__init__.py,sha256=ujBvX-GY4Pg4ACBh7RXm_MOmi2eAowf5s7pG2SXWdpo,2276
|
|
2
|
+
django_bulk_hooks/changeset.py,sha256=wU6wckJEQ_hG5UZq_9g_kWODoKwEj99JrtacVUQ9BxA,7445
|
|
3
|
+
django_bulk_hooks/conditions.py,sha256=v2DMFmWI7bppBQw5qdbO5CmQRN_QtUwnBjcyKBJLLbw,8030
|
|
4
|
+
django_bulk_hooks/constants.py,sha256=PxpEETaO6gdENcTPoXS586lerGKVP3nmjpDvOkmhYxI,509
|
|
5
|
+
django_bulk_hooks/context.py,sha256=mqaC5-yESDTA5ruI7fuXlt8qSgKuOFp0mjq7h1-4HdQ,1926
|
|
6
|
+
django_bulk_hooks/decorators.py,sha256=P7cvzFgORJRW-YQHNAxNXqQOP9OywBmA7Rz9kiJoxUk,12237
|
|
7
|
+
django_bulk_hooks/dispatcher.py,sha256=fOWh1gtukdegMgku7qdc-Hix6G6ZCKMetONFiNKIBWI,8842
|
|
8
|
+
django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
|
|
9
|
+
django_bulk_hooks/factory.py,sha256=OgrOmLbIzhrSKTDx06oGMAVsEb0NoVOmW5IdLsMz_Qs,19938
|
|
10
|
+
django_bulk_hooks/handler.py,sha256=i0M4mdx3vgXIb8mA1S5ZBW_8ezECd8yTZaj9QNUm8P8,4738
|
|
11
|
+
django_bulk_hooks/helpers.py,sha256=Nw8eXryLUUquW7AgiuKp0PQT3Pq6HAHsdP-xAtqhmjA,3216
|
|
12
|
+
django_bulk_hooks/manager.py,sha256=3mFzB0ZzHHeXWdKGObZD_H0NlskHJc8uYBF69KKdAXU,4068
|
|
13
|
+
django_bulk_hooks/models.py,sha256=4Vvi2LiGP0g4j08a5liqBROfsO8Wd_ermBoyjKwfrPU,2512
|
|
14
|
+
django_bulk_hooks/operations/__init__.py,sha256=BtJYjmRhe_sScivLsniDaZmBkm0ZLvcmzXFKL7QY2Xg,550
|
|
15
|
+
django_bulk_hooks/operations/analyzer.py,sha256=8xNdsoeOCHsIIP7ztIuFHDewBR2dDSS6auOrSU8zmqE,9007
|
|
16
|
+
django_bulk_hooks/operations/bulk_executor.py,sha256=QmfcEUJAVHaMPzYe4yDwQ0i-9FvxDaTWy17mcmn2-Yw,22371
|
|
17
|
+
django_bulk_hooks/operations/coordinator.py,sha256=iSi-x3fq6_3UygWGeQY8Fq_gZWIqq_8N7WddPhVeygk,23526
|
|
18
|
+
django_bulk_hooks/operations/mti_handler.py,sha256=G-pxkzIqHqXGshRGksqmsN1J3rlzePUZrSv4wm7D3cQ,19162
|
|
19
|
+
django_bulk_hooks/operations/mti_plans.py,sha256=YP7LcV9Z8UqNS_x74OswF9_5swqruRTdAu6z-J_R6C0,3377
|
|
20
|
+
django_bulk_hooks/operations/record_classifier.py,sha256=KzUoAhfoqzFVrOabNZAby9Akb54h-fAQZmb8O-fIx_0,6221
|
|
21
|
+
django_bulk_hooks/queryset.py,sha256=rvJgQLwtSJztwc68nkJ6xwCsnbXQvkvS6_dbGGj8TFo,5886
|
|
22
|
+
django_bulk_hooks/registry.py,sha256=QyeA2OqNdMAMaLjFU9UF0YGhKiPKbZkmFQpLgof7uNs,9038
|
|
23
|
+
django_bulk_hooks-0.2.17.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
|
|
24
|
+
django_bulk_hooks-0.2.17.dist-info/METADATA,sha256=ue7kA8E8s2Tha6v_EXhQ41oORwxZ1rTWMem14TNqLGg,9265
|
|
25
|
+
django_bulk_hooks-0.2.17.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
26
|
+
django_bulk_hooks-0.2.17.dist-info/RECORD,,
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
django_bulk_hooks/__init__.py,sha256=4QlWY5rqR9o2ddrNB-ypM4s1GtNJ1ZvL2ABhybaPpio,1823
|
|
2
|
-
django_bulk_hooks/changeset.py,sha256=WALeiWDcjOBNdCKeidVKOPKAySKj9ZOvUJ-kWaVZYhM,7444
|
|
3
|
-
django_bulk_hooks/conditions.py,sha256=qtGjToKXC8FPUPK31Mib-GMzc9GSdrH90M2pT3CIsh8,8111
|
|
4
|
-
django_bulk_hooks/constants.py,sha256=PxpEETaO6gdENcTPoXS586lerGKVP3nmjpDvOkmhYxI,509
|
|
5
|
-
django_bulk_hooks/context.py,sha256=mqaC5-yESDTA5ruI7fuXlt8qSgKuOFp0mjq7h1-4HdQ,1926
|
|
6
|
-
django_bulk_hooks/decorators.py,sha256=uZhMGbFUxMz8fNnWBltB1D5Ez1d6vRNvoSFzqOTdGDo,12331
|
|
7
|
-
django_bulk_hooks/dispatcher.py,sha256=ExEtApzwvprWIlbZifPUY17hJHeRUmeHe59BikDgs_g,8872
|
|
8
|
-
django_bulk_hooks/enums.py,sha256=Zo8_tJzuzZ2IKfVc7gZ-0tWPT8q1QhqZbAyoh9ZVJbs,381
|
|
9
|
-
django_bulk_hooks/factory.py,sha256=JmjQiJPfAnytXrO6r6qOadX5yX0-sfpbZ9V8nwX3MAg,20013
|
|
10
|
-
django_bulk_hooks/handler.py,sha256=2-k0GPWGSQ6acfvV0qJgDH8aa0z51DqdpX5vSJ6Uawk,4759
|
|
11
|
-
django_bulk_hooks/helpers.py,sha256=Yopvl588VbKOi2kHEsQcEcI5jw5jiNA2MuF6Ce1VP0c,3174
|
|
12
|
-
django_bulk_hooks/manager.py,sha256=3mFzB0ZzHHeXWdKGObZD_H0NlskHJc8uYBF69KKdAXU,4068
|
|
13
|
-
django_bulk_hooks/models.py,sha256=62tn5wL55EjJVOsZofMluhEJB8bH7CzBvH0vd214_RY,2570
|
|
14
|
-
django_bulk_hooks/operations/__init__.py,sha256=5L5NnwiFw8Yn5WO6-38eGdCYBkA0URpwyDcAdeYfc5w,550
|
|
15
|
-
django_bulk_hooks/operations/analyzer.py,sha256=s6FM53ho1raPdKU-VjjW0SWymXyrJe0I_Wu8XsXFdSY,9065
|
|
16
|
-
django_bulk_hooks/operations/bulk_executor.py,sha256=MqfcwFNvAxpe1pfFfPEq70z8Ft1IxW1fmieDHeWbbbI,22767
|
|
17
|
-
django_bulk_hooks/operations/coordinator.py,sha256=T9Y1Y5BAichETCG23mwC0eQ7VdZde-kUBKWKJVk3L1M,23717
|
|
18
|
-
django_bulk_hooks/operations/mti_handler.py,sha256=y7tHDe2sPVg4bU0y4ITguMUdERwYXvfvjgSD-uvDBEM,19591
|
|
19
|
-
django_bulk_hooks/operations/mti_plans.py,sha256=W2NjG0W9alY2ZxplzHgQv3TvWWmam-8pZuI0YU7HUqA,3365
|
|
20
|
-
django_bulk_hooks/operations/record_classifier.py,sha256=ny_9Z0ATSX-X6I51ufuQUzgGKM0j3IcPs9SMOcgy5oc,6335
|
|
21
|
-
django_bulk_hooks/queryset.py,sha256=ody4MXrRREL27Ts2ey1UpS0tb5Dxnw-6kN3unxPQ3zY,5860
|
|
22
|
-
django_bulk_hooks/registry.py,sha256=fYNY4UzM4evNVozndeVeyD-yL1h0Lf8iykqJ3WqnMc8,9349
|
|
23
|
-
django_bulk_hooks-0.2.16.dist-info/LICENSE,sha256=dguKIcbDGeZD-vXWdLyErPUALYOvtX_fO4Zjhq481uk,1088
|
|
24
|
-
django_bulk_hooks-0.2.16.dist-info/METADATA,sha256=oDkpbXEOpjzhwtAlHboZDSSi_E-HrZ95D6_IoW85ufE,9265
|
|
25
|
-
django_bulk_hooks-0.2.16.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
26
|
-
django_bulk_hooks-0.2.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|