diff --git a/hed/models/query_handler.py b/hed/models/query_handler.py index 0cc404b9f..e1c65a41f 100644 --- a/hed/models/query_handler.py +++ b/hed/models/query_handler.py @@ -16,9 +16,9 @@ def __init__(self, expression_string): 'Event' - Finds any strings with Event, or a descendent tag of Event such as Sensory-event. - 'Event and Action' - Find any strings with Event and Action, including descendant tags. + 'Event && Action' - Find any strings with Event and Action, including descendant tags. - 'Event or Action' - Same as above, but it has either. + 'Event || Action' - Same as above, but it has either. '"Event"' - Finds the Event tag, but not any descendent tags. @@ -26,17 +26,17 @@ def __init__(self, expression_string): 'Eve*' - Find any short tags that begin with Eve*, such as Event, but not Sensory-event. - '[Event and Action]' - Find a group that contains both Event and Action(at any level). + '[Event && Action]' - Find a group that contains both Event and Action(at any level). - '{Event and Action}' - Find a group with Event And Action at the same level. + '{Event && Action}' - Find a group with Event And Action at the same level. - '{Event and Action:}' - Find a group with Event And Action at the same level, and nothing else. + '{Event && Action:}' - Find a group with Event And Action at the same level, and nothing else. - '{Event and Action:Agent}' - Find a group with Event And Action at the same level, and optionally an Agent tag. + '{Event && Action:Agent}' - Find a group with Event And Action at the same level, and optionally an Agent tag. Practical Complex Example: - {(Onset or Offset), (Def or {Def-expand}): ???} - A group with an onset tag, + {(Onset || Offset), (Def || {Def-expand}): ???} - A group with an onset tag, a def tag or def-expand group, and an optional wildcard group Parameters: @@ -96,7 +96,7 @@ def _tokenize(expression_string): """Tokenize the expression string into a list""" grouping_re = r"\[\[|\[|\]\]|\]|}|{|:" paren_re = r"\)|\(|~" - word_re = r"\?+|\band\b|\bor\b|,|[\"_\-a-zA-Z0-9/.^#\*@]+" + word_re = r"\?+|\&\&|\|\||,|[\"_\-a-zA-Z0-9/.^#\*@]+" re_string = fr"({grouping_re}|{paren_re}|{word_re})" token_re = re.compile(re_string) diff --git a/hed/models/query_util.py b/hed/models/query_util.py index 2ee906f14..6acb1c2bc 100644 --- a/hed/models/query_util.py +++ b/hed/models/query_util.py @@ -59,8 +59,8 @@ class Token: def __init__(self, text): tokens = { ",": Token.And, - "and": Token.And, - "or": Token.Or, + "&&": Token.And, + "||": Token.Or, "[": Token.DescendantGroup, "]": Token.DescendantGroupEnd, "(": Token.LogicalGroup, diff --git a/tests/models/test_query_handler.py b/tests/models/test_query_handler.py index 0e33d6311..7989b3014 100644 --- a/tests/models/test_query_handler.py +++ b/tests/models/test_query_handler.py @@ -38,9 +38,9 @@ def base_test(self, parse_expr, search_strings): def test_broken_search_strings(self): test_search_strings = [ - "A and", - "(A and B", - "and B", + "A &&", + "(A && B", + "&& B", "A, ", ", A", "A)" @@ -58,7 +58,7 @@ def test_finding_tags(self): "Agent, Clear-throat": True, "Agent, Event": False, } - self.base_test("(Item or Agent) and Action", test_strings) + self.base_test("(Item || Agent) && Action", test_strings) def test_finding_tags_wildcards(self): test_strings = { @@ -118,7 +118,7 @@ def test_finding_tags2(self): "Agent, (Event)": True, "(Item), (Event)": True } - self.base_test("(Item or Agent) and {Action or Event}", test_strings) + self.base_test("(Item || Agent) && {Action || Event}", test_strings) def test_exact_group(self): test_strings = { @@ -163,7 +163,7 @@ def test_duplicate_search(self): "(Event, Agent-action)": True, } - self.base_test("Event and Event", test_strings) + self.base_test("Event && Event", test_strings) def test_duplicate_search_or(self): test_strings = { @@ -171,7 +171,7 @@ def test_duplicate_search_or(self): "(Event, Agent-action)": True, } - self.base_test("Event or Event", test_strings) + self.base_test("Event || Event", test_strings) def test_exact_group_complex_split(self): test_strings = { @@ -210,7 +210,7 @@ def test_exact_group_split_or(self): "((A), ((D)))": True, "((A, D))": True, } - self.base_test("{ {a} or {d} }", test_strings) + self.base_test("{ {a} || {d} }", test_strings) def test_exact_group_split_or_negation(self): test_strings = { @@ -234,7 +234,7 @@ def test_exact_group_split_or_negation_dual(self): "((A), (B, C))": False, "((A), ((B), C))": True, } - self.base_test("{ {~a and ~b} }", test_strings) + self.base_test("{ {~a && ~b} }", test_strings) def test_exact_group_split_or_negation_dual2(self): test_strings = { @@ -247,7 +247,7 @@ def test_exact_group_split_or_negation_dual2(self): "((A), (B, C))": False, "((A), ((B), C))": True, } - self.base_test("{ {~(a or b)} }", test_strings) + self.base_test("{ {~(a || b)} }", test_strings) def test_exact_group_split_or_negation_complex(self): test_strings = { @@ -261,7 +261,7 @@ def test_exact_group_split_or_negation_complex(self): "((A), (B, C)), (D)": False, "((A), (B, C)), (H)": False, } - self.base_test("{ {~(a or b)} } and {D or ~F}", test_strings) + self.base_test("{ {~(a || b)} } && {D || ~F}", test_strings) # TODO: Should this work, and what should it mean? # Right now this is always true, since there is at least one group without ", (a)" in every string. @@ -299,7 +299,7 @@ def test_exact_group_negation3(self): "(B)": True, "((A), B)": True } - self.base_test("{ ~a and b}", test_strings) + self.base_test("{ ~a && b}", test_strings) def test_exact_group_negation4(self): test_strings = { @@ -312,10 +312,10 @@ def test_exact_group_negation4(self): "(B, (D))": True, "((A), B)": False } - self.base_test("{ @c and @a and b: ???}", test_strings) + self.base_test("{ @c && @a && b: ???}", test_strings) def test_exact_group_negation5(self): - test_string = "{ ~a and b:}" + test_string = "{ ~a && b:}" with self.assertRaises(ValueError) as context: QueryHandler(test_string) self.assertTrue(context.exception.args[0]) @@ -413,7 +413,7 @@ def test_and(self): "A, C": False, "B, C": False } - self.base_test("a and b", test_strings) + self.base_test("a && b", test_strings) def test_or(self): test_strings = { @@ -424,7 +424,7 @@ def test_or(self): "A, C": True, "B, C": True } - self.base_test("a or b", test_strings) + self.base_test("a || b", test_strings) def test_and_wildcard(self): test_strings = { @@ -438,7 +438,7 @@ def test_and_wildcard(self): "D, A, B": True, "A, B, (C)": True } - self.base_test("a and b and ?", test_strings) + self.base_test("a && b && ?", test_strings) def test_and_wildcard_nothing_else(self): test_strings = { @@ -454,7 +454,7 @@ def test_and_wildcard_nothing_else(self): "(A, B), C": True, "(A, B, C)": True, } - self.base_test("{a and b}", test_strings) + self.base_test("{a && b}", test_strings) test_strings = { "A": False, @@ -469,7 +469,7 @@ def test_and_wildcard_nothing_else(self): "(A, B), C": True, "(A, B, C)": False, } - self.base_test("{a and b:}", test_strings) + self.base_test("{a && b:}", test_strings) def test_and_logical_wildcard(self): test_strings = { @@ -478,8 +478,8 @@ def test_and_logical_wildcard(self): "A, B, (C)": True, "A, B, C": True, } - self.base_test("(A, B) and ?", test_strings) - self.base_test("A, B and ?", test_strings) + self.base_test("(A, B) && ?", test_strings) + self.base_test("A, B && ?", test_strings) test_strings = { "A": True, @@ -488,9 +488,9 @@ def test_and_logical_wildcard(self): "B, C": False, "B, C, D, E": True } - self.base_test("(a or (b and c) and ?)", test_strings) + self.base_test("(a || (b && c) && ?)", test_strings) - self.base_test("(a or (b and c and ?) and ?)", test_strings) + self.base_test("(a || (b && c && ?) && ?)", test_strings) def test_double_wildcard(self): test_strings = { @@ -499,7 +499,7 @@ def test_double_wildcard(self): "A, B, C": True, "A, (B), (C)": False, } - self.base_test("A and ? and ??", test_strings) + self.base_test("A && ? && ??", test_strings) def test_or_wildcard(self): test_strings = { @@ -513,7 +513,7 @@ def test_or_wildcard(self): "D, A, B": True, "A, B, (C)": True } - self.base_test("a or b, ?", test_strings) + self.base_test("a || b, ?", test_strings) def test_and_wildcard_tags(self): test_strings = { @@ -527,7 +527,7 @@ def test_and_wildcard_tags(self): "D, A, B": True, "A, B, (C)": False } - self.base_test("a and b, ??", test_strings) + self.base_test("a && b, ??", test_strings) def test_and_wildcard_groups(self): test_strings = { @@ -541,7 +541,7 @@ def test_and_wildcard_groups(self): "D, A, B": False, "A, B, (C)": True } - self.base_test("a and b, ???", test_strings) + self.base_test("a && b, ???", test_strings) def test_complex_wildcard_groups(self): test_strings = { @@ -560,19 +560,19 @@ def test_complex_wildcard_groups(self): "((A, B), (C)), E": False, # todo: should discuss this case. Is this correct to be False? "((A, B), C), E": False, } - self.base_test("[a and b, ???], ?", test_strings) + self.base_test("[a && b, ???], ?", test_strings) def test_wildcard_new(self): # todo: does it make sense this behavior varies? I think so test_strings = { "((A, B), C)": False, } - self.base_test("[a and b, ???]", test_strings) + self.base_test("[a && b, ???]", test_strings) test_strings = { "((A, B), C)": False, } - self.base_test("[a and b and c]", test_strings) + self.base_test("[a && b && c]", test_strings) def test_complex_wildcard_groups2(self): test_strings = { @@ -589,7 +589,7 @@ def test_complex_wildcard_groups2(self): "(A, B, (C)), D": False, "(A, B, (C)), (D), E": True, } - self.base_test("[a and b, ???], E, ?", test_strings) + self.base_test("[a && b, ???], E, ?", test_strings) def test_and_or(self): test_strings = { @@ -600,7 +600,7 @@ def test_and_or(self): "A, C": True, "B, C": True } - self.base_test("a and b or c", test_strings) + self.base_test("a && b || c", test_strings) test_strings = { "A": False, @@ -610,7 +610,7 @@ def test_and_or(self): "A, C": True, "B, C": True } - self.base_test("(a and b) or c", test_strings) + self.base_test("(a && b) || c", test_strings) test_strings = { "A": False, @@ -620,7 +620,7 @@ def test_and_or(self): "A, C": True, "B, C": False } - self.base_test("a and (b or c)", test_strings) + self.base_test("a && (b || c)", test_strings) test_strings = { "A": True, @@ -630,7 +630,7 @@ def test_and_or(self): "A, C": True, "B, C": True } - self.base_test("a or b and c", test_strings) + self.base_test("a || b && c", test_strings) test_strings = { "A": True, @@ -640,7 +640,7 @@ def test_and_or(self): "A, C": True, "B, C": True } - self.base_test("a or (b and c)", test_strings) + self.base_test("a || (b && c)", test_strings) test_strings = { "A": False, @@ -650,7 +650,7 @@ def test_and_or(self): "A, C": True, "B, C": True } - self.base_test("(a or b) and c", test_strings) + self.base_test("(a || b) && c", test_strings) def test_logical_negation(self): expression = QueryHandler("~a") @@ -659,7 +659,7 @@ def test_logical_negation(self): hed_string = HedString("B", self.hed_schema) self.assertEqual(bool(expression.search(hed_string)), True) - expression = QueryHandler("~a and b") + expression = QueryHandler("~a && b") hed_string = HedString("A", self.hed_schema) self.assertEqual(bool(expression.search(hed_string)), False) hed_string = HedString("B", self.hed_schema) @@ -667,7 +667,7 @@ def test_logical_negation(self): hed_string = HedString("A, B", self.hed_schema) self.assertEqual(bool(expression.search(hed_string)), False) - expression = QueryHandler("~( (a or b) and c)") + expression = QueryHandler("~( (a || b) && c)") hed_string = HedString("A", self.hed_schema) self.assertEqual(bool(expression.search(hed_string)), True) hed_string = HedString("B", self.hed_schema) @@ -711,7 +711,7 @@ def test_not_in_line2(self): "(A, B, (C)), D": False, "(A, B, (C)), (D), E": False, } - self.base_test("@B and C", test_strings) + self.base_test("@B && C", test_strings) def test_not_in_line3(self): test_strings = { @@ -728,24 +728,24 @@ def test_not_in_line3(self): "(A, B, (C)), D": True, "(A, B, (C)), (D), E": True, } - self.base_test("@C or B", test_strings) + self.base_test("@C || B", test_strings) def test_optional_exact_group(self): test_strings = { "(A, C)": True, } - self.base_test("{a and (b or c)}", test_strings) + self.base_test("{a && (b || c)}", test_strings) test_strings = { "(A, B, C, D)": True, } - self.base_test("{a and b: c and d}", test_strings) + self.base_test("{a && b: c && d}", test_strings) test_strings = { "(A, B, C)": True, "(A, B, C, D)": False, } - self.base_test("{a and b: c or d}", test_strings) + self.base_test("{a && b: c || d}", test_strings) test_strings = { "(A, C)": True, @@ -753,7 +753,7 @@ def test_optional_exact_group(self): "(A, B, C)": False, "(A, B, C, D)": False, } - self.base_test("{a or b: c or d}", test_strings) + self.base_test("{a || b: c || d}", test_strings) test_strings = { "(Onset, (Def-expand/taco))": True, @@ -766,9 +766,9 @@ def test_optional_exact_group(self): "Onset, (Def-expand/taco), (Label/OnsetContents)": False, "(Onset, (Def-expand/taco), Label/OnsetContents)": False, } - self.base_test("{(Onset or Offset), (Def or {Def-expand}): ???}", test_strings) + self.base_test("{(Onset || Offset), (Def || {Def-expand}): ???}", test_strings) test_strings = { "(A, B)": True, "(A, B, C)": True } - self.base_test("{a or b}", test_strings) \ No newline at end of file + self.base_test("{a || b}", test_strings) \ No newline at end of file