diff --git a/gracedb/search/constants.py b/gracedb/search/constants.py index abc6adcc6d4627d972972a9a67fa8e9bb66f63a6..3df972b8b417a8833427aac066b15f7ffe020d02 100644 --- a/gracedb/search/constants.py +++ b/gracedb/search/constants.py @@ -1,13 +1,18 @@ +from pyparsing import Literal, Or -# Translate comparison operators to Django queryset filter keywords +# Create a parser for translating comparison operators to +# Django queryset filter keywords EXPR_OPERATORS = { "<" : "__lt", "<=": "__lte", "=" : "", + "==" : "", ":" : "", ">" : "__gt", ">=": "__gte", } +ExpressionOperator = Or(map(Literal, EXPR_OPERATORS.keys())) +ExpressionOperator.setParseAction(lambda toks: EXPR_OPERATORS[toks[0]]) # Dict of LIGO run names (keys) and GPS time range tuples (values) diff --git a/gracedb/search/query/events.py b/gracedb/search/query/events.py index 8f614bfa4658578004e50ed8b0a88daf9b5c821a..0d0d51b576e08820815b9678eafab7fcb9abae3d 100644 --- a/gracedb/search/query/events.py +++ b/gracedb/search/query/events.py @@ -25,7 +25,7 @@ nltime = nltime_.setParseAction(lambda toks: toks["calculatedTime"]) from events.models import Group, Pipeline, Search, Label from .labels import getLabelQ from .superevents import parse_superevent_id, superevent_expr -from ..constants import RUN_MAP, EXPR_OPERATORS +from ..constants import RUN_MAP, ExpressionOperator from ..utils import maybeRange @@ -178,10 +178,8 @@ lhs = delimitedList(Word(alphanums+'_'), '.') lhs.setParseAction(buildDjangoQueryField) rhs = afloat | QuotedString('"') -op = Or(map(Literal, EXPR_OPERATORS.keys())) -op.setParseAction(lambda toks: EXPR_OPERATORS[toks[0]]) -simpleTerm = lhs + op + rhs +simpleTerm = lhs + ExpressionOperator + rhs simpleTerm.setParseAction(lambda toks: Q(**{toks[0]+toks[1]: toks[2]})) rangeTerm = lhs + Suppress('in') + rhs + Suppress(",") + rhs diff --git a/gracedb/search/query/superevents.py b/gracedb/search/query/superevents.py index af0c651cab6b82046b0d6673d7c0425cdc9108ae..1d6b795d06d144af37d9abe14dbe45dd8f02c414 100644 --- a/gracedb/search/query/superevents.py +++ b/gracedb/search/query/superevents.py @@ -12,14 +12,14 @@ from events.models import Group, Pipeline, Search, Label from events.nltime import nlTimeExpression as nltime_ from superevents.models import Superevent from .labels import getLabelQ -from ..constants import RUN_MAP +from ..constants import RUN_MAP, ExpressionOperator from ..utils import maybeRange from pyparsing import Word, nums, Literal, CaselessLiteral, delimitedList, \ Suppress, QuotedString, Keyword, Combine, Or, Optional, OneOrMore, \ ZeroOrMore, alphas, alphanums, Regex, opAssoc, operatorPrecedence, \ oneOf, stringStart, stringEnd, FollowedBy, ParseResults, ParseException, \ - CaselessKeyword + CaselessKeyword, pyparsing_common # Set up logger logger = logging.getLogger(__name__) @@ -171,6 +171,25 @@ parameter_dicts = { Q(category=[t[0] for t in Superevent.SUPEREVENT_CATEGORY_CHOICES if t[1].lower()==toks[0].lower()][0])), }, + # far: 1e-5 SAME AS far == 1e-5. Other options like: far > 1e-5 + 'far': { + 'doRange': False, + 'value': Suppress(CaselessLiteral('far')) + ExpressionOperator + \ + pyparsing_common.number, + 'parseAction': lambda toks: ("far", + Q(**{'preferred_event__far' + toks[0]: toks[1]})), + }, + # far in 1e-5, 1e-4 OR far: 1e-5 - 1e-4 OR far: 1e-5 .. 1e-4 + 'far_range': { + 'doRange': False, + 'value': Suppress(CaselessLiteral('far')) + \ + Suppress(Or([CaselessLiteral(d) for d in ['in', ':']])) + \ + pyparsing_common.number + \ + Suppress(Or([CaselessLiteral(op) for op in [',', '..', '-']])) + \ + pyparsing_common.number, + 'parseAction': lambda toks: ("far_range", + Q(**{'preferred_event__far__range': toks.asList()})), + }, } # Compile a list of expressions to try to match @@ -180,33 +199,35 @@ for k,p in parameter_dicts.iteritems(): # Define val and set name val = p['value'] val.setName(k) + expr = val # Add keyword. Format is keyword: value - if isinstance(p['keyword'], list): - if p.has_key('keywordOptional') and p['keywordOptional']: - keyword_list = [Optional(Suppress(Keyword(k + ":"))) for k in - p['keyword']] + if p.has_key('keyword'): + if isinstance(p['keyword'], list): + if p.has_key('keywordOptional') and p['keywordOptional']: + keyword_list = [Optional(Suppress(Keyword(k + ":"))) for k in + p['keyword']] + else: + keyword_list = [Suppress(Keyword(k + ":")) for k in p['keyword']] + keyword = reduce(lambda x,y: x^y, keyword_list) else: - keyword_list = [Suppress(Keyword(k + ":")) for k in p['keyword']] - keyword = reduce(lambda x,y: x^y, keyword_list) - else: - keyword = Suppress(Keyword(p['keyword'] + ":")) - if p.has_key('keywordOptional') and p['keywordOptional']: - keyword = Optional(keyword) + keyword = Suppress(Keyword(p['keyword'] + ":")) + if p.has_key('keywordOptional') and p['keywordOptional']: + keyword = Optional(keyword) + + # Combine keyword and value into a single expression + expr = keyword + expr # Add range with format: parameter .. parameter if p.has_key('doRange') and p['doRange']: range_val = val + Suppress("..") + val val ^= range_val - # Combine keyword and value into a single expression - full_expr = keyword + val - # Set parse action - full_expr = full_expr.setParseAction(p['parseAction']) + expr = expr.setParseAction(p['parseAction']) # Append to list of all expressions - expr_list.append(full_expr) + expr_list.append(expr) # Compile a combined expression by Or-ing all of the individual expressions combined_expr = Or(expr_list) diff --git a/gracedb/templates/search/query_help_frag.html b/gracedb/templates/search/query_help_frag.html index e9e13519729780780e5f17312732b6e746bb29d4..38d1c8a316433e9f9505fdfe0866594f06fac46b 100644 --- a/gracedb/templates/search/query_help_frag.html +++ b/gracedb/templates/search/query_help_frag.html @@ -160,5 +160,11 @@ </ul> Or, just add either "public" or "internal" to your query. + <h4>By preferred event FAR</h4> + <ul> + <li>far < 1e-5</li> + <li>FAR >= 0.01</li> + <li>far in 1e-7, 2.5e-6</li> + </ul> </div>