Skip to content

Commit f31f1c2

Browse files
Raise error for regex operator
1 parent 14e7201 commit f31f1c2

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

tests/test_filter.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212

1313
class TestFilterExpressionParser:
14+
@pytest.fixture()
15+
def parser(self):
16+
return filter_mod.make_bcftools_filter_parser(map_vcf_identifiers=False)
17+
1418
@pytest.mark.parametrize(
1519
"expression",
1620
[
@@ -20,11 +24,20 @@ class TestFilterExpressionParser:
2024
'"stri + 2',
2125
],
2226
)
23-
def test_invalid_expressions(self, expression):
24-
parser = filter_mod.make_bcftools_filter_parser(map_vcf_identifiers=False)
27+
def test_invalid_expressions(self, parser, expression):
2528
with pytest.raises(pp.ParseException):
2629
parser.parse_string(expression, parse_all=True)
2730

31+
@pytest.mark.parametrize(
32+
("expression", "exception_class"),
33+
[
34+
('INFO/HAYSTACK ~ "needle"', filter_mod.UnsupportedRegexError),
35+
],
36+
)
37+
def test_unsupported_syntax(self, parser, expression, exception_class):
38+
with pytest.raises(exception_class):
39+
parser.parse_string(expression, parse_all=True)
40+
2841

2942
class TestFilterExpressionSample:
3043
@pytest.mark.parametrize(

vcztools/filter.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@
1313
pp.ParserElement.enablePackrat()
1414

1515

16+
class UnsupportedFilteringFeatureError(ValueError):
17+
def __init__(self):
18+
super().__init__(
19+
f"Unsupported filtering feature: {self.feature}. Please see "
20+
f"https://github.com/sgkit-dev/vcztools/issues/{self.issue} "
21+
"for details and let us know if this is important to you."
22+
)
23+
24+
25+
class UnsupportedRegexError(UnsupportedFilteringFeatureError):
26+
issue = "174"
27+
feature = "Regular expressions"
28+
29+
1630
# The parser and evaluation model here are based on the eval_arith example
1731
# in the pyparsing docs:
1832
# https://github.com/pyparsing/pyparsing/blob/master/examples/eval_arith.py
@@ -27,18 +41,18 @@ class EvaluationNode:
2741
def __init__(self, tokens):
2842
self.tokens = tokens[0]
2943

30-
31-
class Constant(EvaluationNode):
32-
def eval(self, data):
33-
return self.tokens
34-
3544
def __repr__(self):
3645
return repr(self.tokens)
3746

3847
def referenced_fields(self):
3948
return frozenset()
4049

4150

51+
class Constant(EvaluationNode):
52+
def eval(self, data):
53+
return self.tokens
54+
55+
4256
class Identifier(EvaluationNode):
4357
def __init__(self, mapper, tokens):
4458
self.field_name = mapper(tokens[0])
@@ -55,6 +69,11 @@ def referenced_fields(self):
5569
return frozenset([self.field_name])
5670

5771

72+
class RegexOperator(EvaluationNode):
73+
def __init__(self, tokens):
74+
raise UnsupportedRegexError()
75+
76+
5877
# NOTE we should perhaps add a Operator superclass of UnaryMinus,
5978
# BinaryOperator and ComparisonOperator to reduce duplication
6079
# when doing things like referenced_fields. We should probably
@@ -175,6 +194,9 @@ def make_bcftools_filter_parser(all_fields=None, map_vcf_identifiers=True):
175194
(pp.Keyword("&&"), 2, pp.OpAssoc.LEFT, BinaryOperator),
176195
(pp.Keyword("|"), 2, pp.OpAssoc.LEFT, BinaryOperator),
177196
(pp.Keyword("||"), 2, pp.OpAssoc.LEFT, BinaryOperator),
197+
# NOTE Putting the Regex operator at the end for now as
198+
# I haven't figured out what the actual precedence is.
199+
(pp.one_of("~ !~"), 2, pp.OpAssoc.LEFT, RegexOperator),
178200
],
179201
)
180202
return filter_expression

0 commit comments

Comments
 (0)