Skip to content

Commit 443a1de

Browse files
authored
refs(search): Add some typing to event_search.py, and refactor convert_search_filter_to_snuba_query to be less huge (#26190)
This should be functionally the same as before, just breaking up `convert_search_filter_to_snuba_query` some.
1 parent b047a33 commit 443a1de

File tree

2 files changed

+260
-176
lines changed

2 files changed

+260
-176
lines changed

src/sentry/api/event_search.py

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import re
22
from collections import namedtuple
33
from datetime import datetime
4+
from typing import NamedTuple, Sequence, Union
45

56
from django.utils.functional import cached_property
67
from parsimonious.exceptions import IncompleteParseError
@@ -138,7 +139,7 @@
138139
)
139140

140141

141-
def translate(pat):
142+
def translate(pat) -> str:
142143
"""Translate a shell PATTERN to a regular expression.
143144
modified from: https://github.com/python/cpython/blob/2.7/Lib/fnmatch.py#L85
144145
"""
@@ -176,70 +177,42 @@ class ParenExpression(namedtuple("ParenExpression", "children")):
176177
pass
177178

178179

179-
class SearchFilter(namedtuple("SearchFilter", "key operator value")):
180-
def __str__(self):
181-
return "".join(map(str, (self.key.name, self.operator, self.value.raw_value)))
182-
183-
@cached_property
184-
def is_negation(self):
185-
# Negations are mostly just using != operators. But we also have
186-
# negations on has: filters, which translate to = '', so handle that
187-
# case as well.
188-
return (
189-
self.operator == "!="
190-
and self.value.raw_value != ""
191-
or self.operator == "="
192-
and self.value.raw_value == ""
193-
or self.operator == "NOT IN"
194-
and self.value.raw_value
195-
)
180+
class SearchKey(NamedTuple):
181+
name: str
196182

197-
@cached_property
198-
def is_in_filter(self):
199-
return self.operator in ("IN", "NOT IN")
200-
201-
202-
class SearchKey(namedtuple("SearchKey", "name")):
203-
@cached_property
204-
def is_tag(self):
183+
@property
184+
def is_tag(self) -> bool:
205185
return TAG_KEY_RE.match(self.name) or (
206186
self.name not in SEARCH_MAP
207187
and self.name not in FIELD_ALIASES
208188
and not self.is_measurement
209189
and not self.is_span_op_breakdown
210190
)
211191

212-
@cached_property
213-
def is_measurement(self):
192+
@property
193+
def is_measurement(self) -> bool:
214194
return is_measurement(self.name) and self.name not in SEARCH_MAP
215195

216-
@cached_property
217-
def is_span_op_breakdown(self):
196+
@property
197+
def is_span_op_breakdown(self) -> bool:
218198
return is_span_op_breakdown(self.name) and self.name not in SEARCH_MAP
219199

220200

221-
class AggregateFilter(namedtuple("AggregateFilter", "key operator value")):
222-
def __str__(self):
223-
return "".join(map(str, (self.key.name, self.operator, self.value.raw_value)))
224-
225-
226-
class AggregateKey(namedtuple("AggregateKey", "name")):
227-
pass
201+
class SearchValue(NamedTuple):
202+
raw_value: Union[str, int, datetime, Sequence[int], Sequence[str]]
228203

229-
230-
class SearchValue(namedtuple("SearchValue", "raw_value")):
231204
@property
232205
def value(self):
233206
if self.is_wildcard():
234207
return translate(self.raw_value)
235208
return self.raw_value
236209

237-
def is_wildcard(self):
210+
def is_wildcard(self) -> bool:
238211
if not isinstance(self.raw_value, str):
239212
return False
240213
return bool(WILDCARD_CHARS.search(self.raw_value))
241214

242-
def is_event_id(self):
215+
def is_event_id(self) -> bool:
243216
"""Return whether the current value is a valid event id
244217
245218
Empty strings are valid, so that it can be used for has:id queries
@@ -249,6 +222,46 @@ def is_event_id(self):
249222
return is_event_id(self.raw_value) or self.raw_value == ""
250223

251224

225+
class SearchFilter(NamedTuple):
226+
key: SearchKey
227+
operator: str
228+
value: SearchValue
229+
230+
def __str__(self):
231+
return "".join(map(str, (self.key.name, self.operator, self.value.raw_value)))
232+
233+
@property
234+
def is_negation(self) -> bool:
235+
# Negations are mostly just using != operators. But we also have
236+
# negations on has: filters, which translate to = '', so handle that
237+
# case as well.
238+
return (
239+
self.operator == "!="
240+
and self.value.raw_value != ""
241+
or self.operator == "="
242+
and self.value.raw_value == ""
243+
or self.operator == "NOT IN"
244+
and self.value.raw_value
245+
)
246+
247+
@property
248+
def is_in_filter(self) -> bool:
249+
return self.operator in ("IN", "NOT IN")
250+
251+
252+
class AggregateFilter(NamedTuple):
253+
key: SearchKey
254+
operator: str
255+
value: SearchValue
256+
257+
def __str__(self):
258+
return "".join(map(str, (self.key.name, self.operator, self.value.raw_value)))
259+
260+
261+
class AggregateKey(NamedTuple):
262+
name: str
263+
264+
252265
class SearchVisitor(NodeVisitor):
253266
# A list of mappers that map source keys to a target name. Format is
254267
# <target_name>: [<list of source names>],

0 commit comments

Comments
 (0)