diff --git a/src/backend/models/filters.py b/src/backend/models/filters.py index 0c9a2439..4cb519e3 100644 --- a/src/backend/models/filters.py +++ b/src/backend/models/filters.py @@ -33,42 +33,47 @@ class ModelFilter(ModelProxy): value: "ModelItem", _changed_fields: Optional[Dict[str, Any]] = None, ) -> None: - if self.accept_source(source): - value = self.convert_item(value) + with self.write_lock: + if self.accept_source(source): + value = self.convert_item(value) - if self.accept_item(value): - self.__setitem__((source.sync_id, key), value, _changed_fields) - self.filtered_out.pop((source.sync_id, key), None) - else: - self.filtered_out[source.sync_id, key] = value - self.pop((source.sync_id, key), None) + if self.accept_item(value): + self.__setitem__( + (source.sync_id, key), value, _changed_fields, + ) + self.filtered_out.pop((source.sync_id, key), None) + else: + self.filtered_out[source.sync_id, key] = value + self.pop((source.sync_id, key), None) - for callback in self.items_changed_callbacks: - callback() + for callback in self.items_changed_callbacks: + callback() def source_item_deleted(self, source: Model, key) -> None: - if self.accept_source(source): - try: - del self[source.sync_id, key] - except KeyError: - del self.filtered_out[source.sync_id, key] + with self.write_lock: + if self.accept_source(source): + try: + del self[source.sync_id, key] + except KeyError: + del self.filtered_out[source.sync_id, key] - for callback in self.items_changed_callbacks: - callback() + for callback in self.items_changed_callbacks: + callback() def source_cleared(self, source: Model) -> None: - if self.accept_source(source): - for source_sync_id, key in self.copy(): - if source_sync_id == source.sync_id: - try: - del self[source.sync_id, key] - except KeyError: - del self.filtered_out[source.sync_id, key] + with self.write_lock: + if self.accept_source(source): + for source_sync_id, key in self.copy(): + if source_sync_id == source.sync_id: + try: + del self[source.sync_id, key] + except KeyError: + del self.filtered_out[source.sync_id, key] - for callback in self.items_changed_callbacks: - callback() + for callback in self.items_changed_callbacks: + callback() def refilter( diff --git a/src/backend/models/model.py b/src/backend/models/model.py index adbd4a29..3ba20d63 100644 --- a/src/backend/models/model.py +++ b/src/backend/models/model.py @@ -188,27 +188,28 @@ class Model(MutableMapping): and one `ModelItemDeleted` pyotherside event is fired per sequence. """ - try: - self._active_batch_remove_indice = [] - yield None - finally: - indice = self._active_batch_remove_indice - groups = [list(group) for item, group in itertools.groupby(indice)] - last = None + with self.write_lock: + try: + self._active_batch_remove_indice = [] + yield None + finally: + indice = self._active_batch_remove_indice + groups = [list(group) for item, group in itertools.groupby(indice)] + last = None - if groups: - last = groups[-1].pop() - if not groups[-1]: - del groups[-1] + if groups: + last = groups[-1].pop() + if not groups[-1]: + del groups[-1] - for grp in groups: - ModelItemDeleted(self.sync_id, index=grp[0], count=len(grp)) + for grp in groups: + ModelItemDeleted(self.sync_id, index=grp[0], count=len(grp)) - # Seems QML ListView has an horrible bug where removing a large - # amount of items at once will result in a corrupted empty display, - # this dumb workaround is the only way I've found - if last: - time.sleep(0.2) - ModelItemDeleted(self.sync_id, index=last, count=1) + # Seems QML ListView has an horrible bug where removing a large + # amount of items at once will result in a corrupted empty display, + # this dumb workaround is the only way I've found + if last: + time.sleep(0.2) + ModelItemDeleted(self.sync_id, index=last, count=1) - self._active_batch_remove_indice = None + self._active_batch_remove_indice = None diff --git a/src/backend/models/proxy.py b/src/backend/models/proxy.py index 8bbfab9a..5a8df83e 100644 --- a/src/backend/models/proxy.py +++ b/src/backend/models/proxy.py @@ -17,10 +17,11 @@ class ModelProxy(Model): self.take_items_ownership = False Model.proxies[sync_id] = self - for sync_id, model in Model.instances.items(): - if sync_id != self.sync_id and self.accept_source(model): - for key, item in model.items(): - self.source_item_set(model, key, item) + with self.write_lock: + for sync_id, model in Model.instances.items(): + if sync_id != self.sync_id and self.accept_source(model): + for key, item in model.items(): + self.source_item_set(model, key, item) def accept_source(self, source: Model) -> bool: