Skip to content

Commit 21eb347

Browse files
committed
!squash extract
1 parent 0767564 commit 21eb347

File tree

1 file changed

+83
-77
lines changed

1 file changed

+83
-77
lines changed

libvcs/utils/list_query.py

Lines changed: 83 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import dataclasses
22
import re
33
import traceback
4-
from typing import Any, Callable, Generic, Optional, Sequence, TypeVar, Union
4+
from typing import Any, Callable, Generic, Optional, Protocol, Sequence, TypeVar, Union
55

66
T = TypeVar("T", Any, Any)
77

@@ -45,6 +45,80 @@ def parse_lookup(obj, path, lookup):
4545
return None
4646

4747

48+
class LookupProtocol(Protocol):
49+
def __call__(self, data: Union[list[str], str], rhs: Union[list[str], str]):
50+
pass
51+
52+
53+
def lookup_exact(data, rhs):
54+
return rhs == data
55+
56+
57+
def lookup_iexact(data, rhs):
58+
return rhs.lower() == data.lower()
59+
60+
61+
def lookup_contains(data, rhs):
62+
return rhs in data
63+
64+
65+
def lookup_icontains(data, rhs):
66+
return rhs.lower() in data.lower()
67+
68+
69+
def lookup_startswith(data, rhs):
70+
return data.startswith(rhs)
71+
72+
73+
def lookup_istartswith(data, rhs):
74+
return data.lower().startswith(rhs.lower())
75+
76+
77+
def lookup_endswith(data, rhs):
78+
return data.endswith(rhs)
79+
80+
81+
def lookup_iendswith(data, rhs):
82+
return data.lower().endswith(rhs.lower())
83+
84+
85+
def lookup_in(data, rhs):
86+
if isinstance(rhs, list):
87+
return data in rhs
88+
return rhs in data
89+
90+
91+
def lookup_nin(data, rhs):
92+
if isinstance(rhs, list):
93+
return data not in rhs
94+
return rhs not in data
95+
96+
97+
def lookup_regex(data, rhs):
98+
return re.search(rhs, data)
99+
100+
101+
def lookup_iregex(data, rhs):
102+
return re.search(rhs, data, re.IGNORECASE)
103+
104+
105+
LOOKUP_NAME_MAP: dict[str, LookupProtocol] = {
106+
"eq": lookup_exact,
107+
"exact": lookup_exact,
108+
"iexact": lookup_iexact,
109+
"contains": lookup_contains,
110+
"icontains": lookup_icontains,
111+
"startswith": lookup_startswith,
112+
"istartswith": lookup_istartswith,
113+
"endswith": lookup_endswith,
114+
"iendswith": lookup_iendswith,
115+
"in": lookup_in,
116+
"nin": lookup_nin,
117+
"regex": lookup_regex,
118+
"iregex": lookup_iregex,
119+
}
120+
121+
48122
@dataclasses.dataclass(eq=False)
49123
class ListQuery(Generic[T]):
50124
"""Filter a list of dicts. *Experimental and unstable*.
@@ -119,93 +193,25 @@ def __eq__(self, other):
119193
return True
120194
return False
121195

122-
def lookup_exact(self, data, rhs):
123-
return rhs == data
124-
125-
def lookup_iexact(self, data, rhs):
126-
return rhs.lower() == data.lower()
127-
128-
def lookup_contains(self, data, rhs):
129-
return rhs in data
130-
131-
def lookup_icontains(self, data, rhs):
132-
return rhs.lower() in data.lower()
133-
134-
LOOKUP_NAME_MAP = {
135-
"contains": lookup_contains,
136-
"icontains": lookup_icontains,
137-
"exact": lookup_exact,
138-
"iexact": lookup_iexact,
139-
}
140-
141196
def filter(self, matcher: Optional[Union[Callable[[T], bool], T]] = None, **kwargs):
142197
def filter_lookup(obj) -> bool:
143198

144199
for path, v in kwargs.items():
145200
try:
146201
lhs, op = path.rsplit("__", 1)
202+
203+
if op not in LOOKUP_NAME_MAP:
204+
raise ValueError(f"{op} not in LOOKUP_NAME_MAP")
147205
except ValueError:
148206
lhs = path
149207
op = "exact"
150208

151-
# assert op in self.LOOKUP_NAME_MAP
152-
# path = lhs
209+
assert op in LOOKUP_NAME_MAP
210+
path = lhs
211+
data = keygetter(obj, path)
153212

154-
if (field := parse_lookup(obj, path, "__contains")) is not None:
155-
if v not in field:
156-
return False
157-
elif (field := parse_lookup(obj, path, "__icontains")) is not None:
158-
if v.lower() not in field.lower():
159-
return False
160-
elif (field := parse_lookup(obj, path, "__in")) is not None:
161-
if isinstance(v, list):
162-
if field not in v:
163-
return False
164-
else:
165-
if v not in field:
166-
return False
167-
elif (field := parse_lookup(obj, path, "__nin")) is not None:
168-
if isinstance(v, list):
169-
if field in v:
170-
return False
171-
else:
172-
if v in field:
173-
return False
174-
elif (field := parse_lookup(obj, path, "__startswith")) is not None:
175-
if not field.startswith(v):
176-
return False
177-
elif (field := parse_lookup(obj, path, "__istartswith")) is not None:
178-
if not field.lower().startswith(v.lower()):
179-
return False
180-
elif (field := parse_lookup(obj, path, "__endswith")) is not None:
181-
if not field.endswith(v):
182-
return False
183-
elif (field := parse_lookup(obj, path, "__iendswith")) is not None:
184-
if not field.lower().endswith(v.lower()):
185-
return False
186-
elif (field := parse_lookup(obj, path, "__regex")) is not None:
187-
if not re.search(v, field):
188-
return False
189-
elif (field := parse_lookup(obj, path, "__iregex")) is not None:
190-
if not re.search(v, field, re.IGNORECASE):
191-
return False
192-
elif (field := parse_lookup(obj, path, "__iexact")) is not None:
193-
if field.lower() != v.lower():
194-
return False
195-
elif (
196-
field := parse_lookup(obj, path, "__exact")
197-
) is not None: # same as else
198-
if field != v:
199-
return False
200-
elif (
201-
field := parse_lookup(obj, path, "__eq")
202-
) is not None: # same as else
203-
if field != v:
204-
return False
205-
else:
206-
if (field := keygetter(obj, path)) is not None: # same as else
207-
if field != v:
208-
return False
213+
if not LOOKUP_NAME_MAP[op](data, v):
214+
return False
209215

210216
return True
211217

0 commit comments

Comments
 (0)