def test_parsing_with_no_localized_grammars(self): mgr = EvaluableParseManager(self.symbol_table, Grammar()) parse_tree1 = mgr.parse('message == "2009-07-13"') parse_tree2 = mgr.parse('message == "2009-07-13"', None) expected_tree = EvaluableParseTree( Equal(String("Hello world"), String("2009-07-13"))) eq_(parse_tree1, parse_tree2) eq_(parse_tree1, expected_tree)
def get_boolean_evaluator(statment, variables=None, constants=None, grammar_tokens=None): """ an fast and easy to use helper to build a parser with variables and constants. return a callable which take a dict of value (for the variables). the returning scope will cotains the variables as is, and the constants into the namespace ``const:`` ie: 'age < const:majority & "o" in name & birthdate > "1983-02-02"' :param str statment: the statment to use :param list|tuple variables: the sample of variables :param dict constants: the value for the consts :param dict grammar_tokens: all extra parameters must be a valid grammar token replacements. (is_subset='in') :return: the parse tree that, if called, return a boolean result :rtype: :class:`booleano.parser.trees.ParseTree` """ grammar_tokens = grammar_tokens or {} grammar = Grammar(**grammar_tokens) if variables is None: variables = [{}] root_table = variable_symbol_table_builder('root', variables[0]) """:type: booleano.parser.scope.SymbolTable""" if constants: root_table.add_subtable( constants_symbol_table_builder('const', constants), ) parse_manager = EvaluableParseManager(root_table, grammar) return parse_manager.parse(statment)
def _solve_rules(self, rules, metrics): """ solve the rules using the given metrics. metrics must contains all needed metrics. :param list[Rule] rules: the :param metrics: :return: :raises: pyparsing.ParseException """ results = {} root_table = SymbolTable('root', ()) for metric_name, values in metrics.items(): # bind to allow "rmq & rmq:xxx" root_table.add_object(Bind(metric_name, Constant(bool(values)))) # bind to allow "rmq:latency" etc root_table.add_subtable( SymbolTable( metric_name, tuple(Bind(k, Constant(v)) for k, v in values.items()))) # build the symbol table for all rules (as boolean) rules_symbols = SymbolTable('rules', ()) root_table.add_subtable(rules_symbols) for rule in rules: rule_name_ = rule['name'] rules_symbols.add_object( Bind( rule_name_, BooleanVariable( partial(get_rule_result, rule_name=rule_name_, rule=rule)))) rules_symbols.add_subtable( SymbolTable(rule_name_, (Bind( 'since', DurationVariable( partial(get_since, rule_name=rule_name_, rule=rule))), ))) parse_manager = EvaluableParseManager(root_table, grammar) for rule in rules: expression_ = rule['expression'] try: results[rule['name']] = parse_manager.parse(expression_)( results) except pyparsing.ParseException as e: logger.debug("error while parsing %r: %s", expression_, e) raise return results
def test_parsing_with_localized_grammars(self): castilian_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar(), es=castilian_grammar) parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3,00", "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3.0))) eq_(parse_tree, expected_tree)
def test_adding_grammar(self): """It should be possible to add grammars after instantiation.""" castilian_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar()) mgr.add_parser("es", castilian_grammar) parse_tree = mgr.parse(u'tráfico:peatones_cruzando_calle <= 3,00', "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3.0))) eq_(parse_tree, expected_tree)
def test_parsing_with_defined_grammar_but_no_available_translations(self): """ When an expression is written in an supported grammar but there are no translated bindings, the default names must be used along with the custom grammar. """ french_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar(), fr=french_grammar) # French grammar is not supported: parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3,0", "fr") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree)
def test_parsing_with_undefined_grammar_and_no_translated_bindings(self): """ When an expression is written in an unsupported grammar, a parser based on the generic grammar must be created and used. If there are no translated bindings, the default names must be used. """ log_handler = LoggingHandlerFixture() mgr = EvaluableParseManager(self.symbol_table, Grammar()) # French grammar is not supported: parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3.0", "fr") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) # Checking the log: info = "Generated parser for unknown grammar %s" % repr('fr') ok_(info in log_handler.handler.messages['info']) log_handler.undo()
def test_parsing_with_undefined_grammar_but_available_translations(self): """ When an expression is written in an unsupported grammar, a parser based on the generic grammar must be created and used. The respective translated bindings must be used if available. """ log_handler = LoggingHandlerFixture() mgr = EvaluableParseManager(self.symbol_table, Grammar()) # Castilian grammar is not supported: parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3.0", "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) # Checking the log: info = "Generated parser for unknown grammar %s" % repr(u'es') ok_(info in log_handler.handler.messages['info']) log_handler.undo()
# 2: create the parser with se symbol table and the grammar (customized) grammar = Grammar(belongs_to='in') parse_manager = EvaluableParseManager(root_table, grammar) # 3: compile a expression # compiled_expression = parse_manager.parse('age < majority & "o" in name & birthdate > "1983-02-02"') # check the command line args if len(sys.argv) == 1: print("try something like %s '\"a\" in name'" % sys.argv[0]) exit(1) stmt = " ".join(sys.argv[1:]) print("searching with expression %r" % stmt) try: compiled_expression = parse_manager.parse(stmt) except pyparsing.ParseException as e: attrs = dict(expr=stmt, e=e, tild='^', grammar="\n".join( "%s => '%s'" % (k, v) for k, v in grammar.get_all_tokens().items())) msg = "error while parsing the expression {expr} at {e.lineno}:{e.col}: {e}\n" \ "{e.line}\n" \ "{tild:->{e.col}}\n" \ " valid grammar : {grammar}".format(**attrs) print(msg) exit(2) else: # run the rule for all sample data
Bind('name', name), Bind('training', DurationVariable('training')), Bind('bending', SetVariable('bending')), ]), SymbolTable('consts', [ Bind('majority', Number(18)), ])) grammar = Grammar(**{'and': 'and', 'or': 'or', 'belongs_to': 'in'}) # 2: create the parser with se symbol table and the grammar (customized) parse_manager = EvaluableParseManager(symbols, grammar) # 3: compile a expression compiled_expression = parse_manager.parse( 'character:age < consts:majority and ' '"a" in character and ' '(' ' {"water"} in character:bending or ' ' character:training > "3d4h"' ')') sample = [ { "name": "katara", "age": 14, "training": datetime.timedelta(days=24), "bending": {'water'} }, { "name": "aang", "age": 112, "training": datetime.timedelta(days=6 * 365),