diff --git a/libvcs/utils/query_list.py b/libvcs/utils/query_list.py index 6c6456df3..4d0a4c503 100644 --- a/libvcs/utils/query_list.py +++ b/libvcs/utils/query_list.py @@ -1,6 +1,7 @@ +import dataclasses import re import traceback -from typing import Any, Callable, Optional, Protocol, Sequence, TypeVar, Union +from typing import Any, Callable, Generic, Optional, Protocol, Sequence, TypeVar, Union T = TypeVar("T", Any, Any) @@ -120,9 +121,13 @@ def lookup_iregex(data, rhs): } -class QueryList(list[T]): +@dataclasses.dataclass(eq=False) +class QueryList(Generic[T]): """Filter list of object/dicts. For small, local datasets. *Experimental, unstable*. + :py:func:`dataclasses.dataclass` is only used for ``__repr__`` and pytest comparison + details. + >>> query = QueryList( ... [ ... { @@ -139,35 +144,44 @@ class QueryList(list[T]): ... }, ... ] ... ) - >>> query.filter(place="Chicago suburbs")[0]['city'] + >>> query.filter(place="Chicago suburbs").data[0]['city'] 'Elmhurst' - >>> query.filter(place__icontains="chicago")[0]['city'] + >>> query.filter(place__icontains="chicago").data[0]['city'] 'Elmhurst' - >>> query.filter(foods__breakfast="waffles")[0]['city'] + >>> query.filter(foods__breakfast="waffles").data[0]['city'] 'Elmhurst' - >>> query.filter(foods__fruit__in="cantelope")[0]['city'] + >>> query.filter(foods__fruit__in="cantelope").data[0]['city'] 'Elmhurst' - >>> query.filter(foods__fruit__in="orange")[0]['city'] + >>> query.filter(foods__fruit__in="orange").data[0]['city'] 'Tampa' """ + __slots__ = ("data", "pk_key") data: Sequence[T] + # def __init__(self, data, pk_key: Optional[str] = None): + # self.data: Sequence[T] = data + # #: Primary key for objects, optional. + # #: Use for .get(), .items() + # self.pk_key: Optional[Any] = pk_key + def items(self): data: Sequence[T] if self.pk_key is None: raise Exception("items() require a pk_key exists") - return [(getattr(item, self.pk_key), item) for item in self] + return [(getattr(item, self.pk_key), item) for item in self.data] def __eq__(self, other): data = other + if hasattr(data, "data"): + data = getattr(data, "data") - if not isinstance(self, list) or not isinstance(data, list): + if not isinstance(self.data, list) or not isinstance(data, list): return False - if len(self) == len(data): - for (a, b) in zip(self, data): + if len(self.data) == len(data): + for (a, b) in zip(self.data, data): if isinstance(a, dict): a_keys = a.keys() if a.keys == b.keys(): @@ -216,4 +230,4 @@ def val_match(obj): else: _filter = filter_lookup - return self.__class__(k for k in self if _filter(k)) + return self.__class__(data=[k for k in self.data if _filter(k)]) diff --git a/tests/utils/test_query_list.py b/tests/utils/test_query_list.py index 6e0da2b17..a2b597cb1 100644 --- a/tests/utils/test_query_list.py +++ b/tests/utils/test_query_list.py @@ -230,7 +230,7 @@ ], ) def test_filter(items: list, filter_expr: Optional[dict], expected_result: list): - qs = QueryList(items) + qs = QueryList(data=items) if filter_expr is not None: if isinstance(filter_expr, dict): assert qs.filter(**filter_expr) == expected_result