Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/operations/filtering/parser.py: 100.00%
22 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-10-04 17:48 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-10-04 17:48 +0000
1# Copyright (C) 2020 Bloomberg LP
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# <http://www.apache.org/licenses/LICENSE-2.0>
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
16from typing import List
18from lark import Lark
19from lark.exceptions import LarkError
21from buildgrid.server.exceptions import InvalidArgumentError
22from buildgrid.server.operations.filtering import OperationFilter
23from buildgrid.server.operations.filtering.interpreter import FilterTreeInterpreter
26class FilterParser:
27 """
28 Utility class primarily used to parse a filter string and return a list a OperationFilters.
29 """
31 lark_parser = Lark.open_from_package(
32 "buildgrid.server.operations.filtering", "filter_grammar.lark", start="filter_phrase"
33 )
35 @staticmethod
36 def parse_listoperations_filters(filter_string: str) -> List[OperationFilter]:
37 """Separate the lowercase filter string into individual components, and return a map containing
38 the relevant filters to use.
40 Filter strings take the following form: key1=value1&key2=value2,value3&key3=value4
41 All spaces in the input are ignored.
43 Filter options are separated with ampersands (&).
44 If a key is repeated, the combined set of values are treated as a logical conjunction (AND).
46 """
47 operation_filters: List[OperationFilter] = []
49 # Handle empty input separately to simplify grammar
50 if not filter_string.strip():
51 return operation_filters
53 try:
54 filter_phrase_tree = FilterParser.lark_parser.parse(filter_string)
55 except LarkError as e:
56 raise InvalidArgumentError(
57 f"Error parsing filter string. See docs for correct filter string syntax. "
58 f"Parser error follows: [{str(e)}]"
59 )
61 try:
62 operation_filters = FilterTreeInterpreter().visit(filter_phrase_tree)
63 except InvalidArgumentError as e:
64 raise InvalidArgumentError(
65 f"Invalid filter string [{filter_string}]. See docs for correct filter string syntax and values."
66 ) from e
68 return operation_filters