Source code for PartSeg.common_backend.partially_const_dict
import itertools
from collections.abc import MutableMapping
from typing import Any, ClassVar, Dict, Generic, Iterator, Tuple, TypeVar, Union
from qtpy.QtCore import QObject, Signal
from PartSeg.common_backend.abstract_class import QtMeta
T = TypeVar("T")
RemovableInfo = Tuple[T, bool]
[docs]class PartiallyConstDict(QObject, MutableMapping, Generic[T], metaclass=QtMeta):
"""
Base class for creating dict to mixin predefined and user defined variables.
"""
item_added = Signal(object)
"""Signal with item added to dict"""
item_removed = Signal(object)
"""Signal with item remove fom dict"""
const_item_dict: ClassVar[Dict[str, Any]] = {}
"""Dict with non removable elements"""
def __init__(self, editable_items):
super().__init__()
self.editable_items = editable_items
self._order_dict = {
name: i for i, name in enumerate(itertools.chain(self.const_item_dict.keys(), editable_items.keys()))
}
self._counter = len(self._order_dict)
def __setitem__(self, key: str, value: Union[T, RemovableInfo]) -> None:
if key in self.const_item_dict:
raise ValueError("Cannot write base item")
self.editable_items[key] = value[0] if isinstance(value, tuple) else value
self._order_dict[key] = self._counter
self._counter += 1
self.item_added.emit(self.editable_items[key])
def __len__(self) -> int:
return len(self.editable_items) + len(self.const_item_dict)
def __iter__(self) -> Iterator[str]:
return itertools.chain(self.const_item_dict, self.editable_items)
def __getitem__(self, key: str) -> RemovableInfo:
try:
if key in self.const_item_dict:
return self.const_item_dict[key], False
return self.editable_items[key], True
except KeyError as e:
raise KeyError(f"Element {key} not found") from e
def __delitem__(self, key: str):
if key in self.const_item_dict:
raise ValueError(f"Cannot delete base item {key}")
item = self.editable_items[key]
del self.editable_items[key]
del self._order_dict[key]
self.item_removed.emit(item)
def _refresh_order(self):
"""workaround for load data problem"""
self._order_dict = {
name: i for i, name in enumerate(itertools.chain(self.const_item_dict.keys(), self.editable_items.keys()))
}
self._counter = len(self._order_dict)
[docs] def get_position(self, key: str) -> int:
"""
Get item position as unique int. For soring purpose
:raise KeyError: if element not in dict
"""
try:
return self._order_dict[key]
except KeyError:
if key not in self:
raise
self._order_dict[key] = self._counter
self._counter += 1
return self._counter - 1