Source code for sr.tools.inventory.query_parser
from pyparsing import oneOf, CaselessKeyword, Forward, Literal, Optional, Or, \
Regex, ZeroOrMore
from sr.tools.inventory import query_ast
TRUE = CaselessKeyword("true")
FALSE = CaselessKeyword("false")
UNSET = CaselessKeyword("unset")
IN = CaselessKeyword("in")
IS = CaselessKeyword("is")
OR = CaselessKeyword("or")
AND = CaselessKeyword("and")
NOT = CaselessKeyword("not")
OF = CaselessKeyword("of")
EQUALS = Literal("=")
COLON = Literal(":")
L_C_BRKT = Literal("{")
R_C_BRKT = Literal("}")
L_BRKT = Literal("(")
R_BRKT = Literal(")")
COMMA = Literal(",")
BANG = Literal("!")
EQUALITY = Or((EQUALS, COLON, IS))
CODE = Literal("code")
SERIAL = Literal("serial")
TYPE = Literal("type")
COND = Or((Literal("condition"), Literal("cond")))
LABELLED = Literal("labelled")
PATH = Literal("path")
ASSY = Literal("assy")
_TRI_STATE_KEY_NAMES = ("development", "v-sense-move-1213",
"motor-rail-mod-1360", "tested",
"has_headers", "velcro-attached",
"cased", "umbilical", "climit_disabled",
"dremel-mod", "tvs-mod-698",
"battery-aa-mod-1270")
TRI_STATE_KEYS = [Literal(x) for x in _TRI_STATE_KEY_NAMES]
ASSET_CODE = Regex(r"(sr)?[a-zA-Z0-9]+")
ASSET_SERIAL = Regex(r"[a-zA-Z0-9\.\*\-\?\[\]]+")
ASSET_NAME = Regex(r"[a-zA-Z0-9\.\*\-\?\[\]]+")
PATH_RE = Regex(r"[a-zA-Z0-9\.\*\-\?\[\]/]+")
CONDITIONS = oneOf("working unknown broken")
# pull registered function names from query_ast
FUNCTIONS = oneOf(' '.join(query_ast.Function.registered_names()))
[docs]def generate_in_expr(prop, val_type):
"""Generate an 'in' expression."""
return (prop + IN + L_C_BRKT +
val_type + ZeroOrMore(COMMA + val_type) +
R_C_BRKT)
code_single = CODE + EQUALITY + ASSET_CODE
code_list = generate_in_expr(CODE, ASSET_CODE)
code_expr = code_list | code_single
serial_single = SERIAL + EQUALITY + ASSET_SERIAL
serial_list = generate_in_expr(SERIAL, ASSET_SERIAL)
serial_expr = serial_list | serial_single
type_single = TYPE + EQUALITY + ASSET_NAME
type_list = generate_in_expr(TYPE, ASSET_NAME)
type_expr = type_list | type_single
cond_single = COND + EQUALITY + CONDITIONS
cond_list = generate_in_expr(COND, CONDITIONS)
cond_expr = cond_list | cond_single
path_single = PATH + EQUALITY + PATH_RE
path_list = generate_in_expr(PATH, PATH_RE)
path_expr = path_list | path_single
label_expr = LABELLED + EQUALITY + Or((TRUE, FALSE))
assy_expr = ASSY + EQUALITY + Or((TRUE, FALSE))
tristate_expr = Or(TRI_STATE_KEYS) + EQUALITY + Or((TRUE, FALSE, UNSET))
or_expr = Forward()
and_expr = Forward()
not_expr = Forward()
primary = Forward()
func_expr = Forward()
base_expr = (not_expr | code_expr | serial_expr | type_expr | cond_expr |
path_expr | label_expr | assy_expr | tristate_expr)
paren_expr = L_BRKT + or_expr + R_BRKT
primary << (base_expr | paren_expr)
func_expr << (FUNCTIONS + OF + func_expr | primary)
and_expr << (func_expr + Optional(AND) + and_expr | func_expr)
or_expr << (and_expr + OR + or_expr | and_expr)
not_expr << Or((NOT, BANG)) + func_expr
root = or_expr
# Parser actions, i.e. AST construction
def _pa_or_expr(x):
if len(x) == 1:
return x[0]
return query_ast.Or(x[0], x[2])
def _pa_and_expr(x):
if len(x) == 1:
return x[0]
if len(x) == 2:
return query_ast.And(x[0], x[1])
return query_ast.And(x[0], x[2])
def _pa_func_expr(x):
if len(x) == 1:
return x[0]
else:
return query_ast.Function(x[0], x[2])
code_single.setParseAction(lambda x: query_ast.Code(x[2]))
code_list.setParseAction(lambda x: query_ast.Code(*x[3::2]))
serial_single.setParseAction(lambda x: query_ast.Serial(x[2]))
serial_list.setParseAction(lambda x: query_ast.Serial(*x[3::2]))
type_single.setParseAction(lambda x: query_ast.Type(x[2]))
type_list.setParseAction(lambda x: query_ast.Type(*x[3::2]))
cond_single.setParseAction(lambda x: query_ast.Condition(x[2]))
cond_list.setParseAction(lambda x: query_ast.Condition(*x[3::2]))
path_single.setParseAction(lambda x: query_ast.Path(x[2]))
path_list.setParseAction(lambda x: query_ast.Path(*x[3::2]))
tristate_expr.setParseAction(lambda x: query_ast.TriState(*x[0::2]))
label_expr.setParseAction(lambda x: query_ast.Labelled(x[2]))
assy_expr.setParseAction(lambda x: query_ast.Assy(x[2]))
or_expr.setParseAction(_pa_or_expr)
and_expr.setParseAction(_pa_and_expr)
func_expr.setParseAction(_pa_func_expr)
not_expr.setParseAction(lambda x: query_ast.Not(x[1]))
paren_expr.setParseAction(lambda x: x[1])
[docs]def search_tree(query):
"""
Create a search tree for a query string.
:param str query: The query string to generate the search tree for.
:returns: A new search tree.
"""
return root.parseString(query)[0]