示例#1
0
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)
示例#2
0
 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)
示例#3
0
    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
示例#4
0
 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)
示例#5
0
 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)
示例#6
0
 def test_evaluating_expressions(self):
     """Managers should be able to evaluate the expressions too."""
     mgr = EvaluableParseManager(self.symbol_table, Grammar())
     context = {'pedestrians_crossroad': (u"gustavo", u"carla")}
     evaluation1 = mgr.evaluate("traffic:pedestrians_crossing_road <= 3",
                                None, context)
     evaluation2 = mgr.evaluate(
         u'"carla" ∈ traffic:pedestrians_crossing_road', None, context)
     evaluation3 = mgr.evaluate("traffic:pedestrians_crossing_road > 2",
                                None, context)
     ok_(evaluation1)
     ok_(evaluation2)
     assert_false(evaluation3)
示例#7
0
    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)
示例#8
0
    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()
示例#9
0
    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()
示例#10
0
    def create_grammar(self):
        root_table = SymbolTable(
            "root",
            map(lambda f: Bind(f['name'], GeometryProperty(f['name'])),
                self.fields))

        tokens = {
            'not': 'not',
            'eq': '==',
            'ne': '!=',
            'belongs_to': 'in',
            'is_subset': 'are included in',
            'or': "or",
            'and': 'and'
        }
        grammar = Grammar(**tokens)
        self.parse_manager = EvaluableParseManager(root_table, grammar)
示例#11
0
 def test_adding_existing_grammar(self):
     """There can't be duplicate/overlapped parsers."""
     mgr = EvaluableParseManager(self.symbol_table, Grammar(), es=Grammar())
     assert_raises(GrammarError, mgr.add_parser, "es", Grammar())
示例#12
0
class TestNativeVariableEvaluableParseManager(object):
    """
    Tests for the :class:`EvaluableParseManager` with caching disabled.

    """

    # A symbol table to be used across the tests:
    symbol_table = SymbolTable(
        "root", (
            Bind("myint", NumberVariable("myint")),
            Bind("mybool", BooleanVariable("mybool")),
            Bind("mystring", StringVariable("mystring")),
            Bind("mydate", DateVariable("mydate")),
            Bind("mydate2", DateVariable("mydate2")),
            Bind("mydatetime", DateTimeVariable("mydatetime")),
            Bind("mydatetime2", DateTimeVariable("mydatetime2")),
            Bind("myset", SetVariable("myset")),
            Bind("myintbis", NumberVariable("myint")),
        ), SymbolTable(
            "sub",
            (Bind("myint", NumberVariable("sub.myint")), ),
        ),
        SymbolTable("const", (
            Bind("hello", String("hello")),
            Bind("li", String("li")),
        )))

    mgr = EvaluableParseManager(
        symbol_table, Grammar(belongs_to='in', is_subset='is subset of'))

    def test_variable_values_myint(self):
        ok_(self.mgr.parse('myint > 0')({'myint': 1}))
        ok_(not self.mgr.parse('myint > 0')({'myint': 0}))
        ok_(self.mgr.parse('myint == 1')({'myint': 1}))
        ok_(not self.mgr.parse('myint == 1')({'myint': 0}))
        ok_(self.mgr.parse('myint < 1')({'myint': 0}))
        ok_(not self.mgr.parse('myint < 0')({'myint': 2}))

    def test_variable_values_mybool(self):
        ok_(self.mgr.parse('mybool')({'mybool': True}))
        ok_(not self.mgr.parse('mybool')({'mybool': False}))
        ok_(self.mgr.parse('mybool > 0')({'mybool': True}))
        ok_(not self.mgr.parse('mybool > 0')({'mybool': False}))
        ok_(self.mgr.parse('mybool == 1')({'mybool': True}))
        ok_(not self.mgr.parse('mybool == 1')({'mybool': False}))
        ok_(self.mgr.parse('mybool < 1')({'mybool': False}))
        ok_(not self.mgr.parse('mybool < 0')({'mybool': True}))

    def test_variable_values_mystring(self):
        mystring = {'mystring': "hello"}
        # equiality
        ok_(self.mgr.parse('mystring == "hello"')(mystring))
        ok_(not self.mgr.parse('mystring != "hello"')(mystring))
        ok_(self.mgr.parse('mystring != "hell"')(mystring))
        ok_(not self.mgr.parse('mystring == "hell"')(mystring))
        # inequality
        ok_(self.mgr.parse('mystring >  "hella"')(mystring))
        ok_(self.mgr.parse('mystring <  "hellz"')(mystring))
        ok_(self.mgr.parse('mystring <  "hellz"')(mystring))
        ok_(self.mgr.parse('mystring <= "hello"')(mystring))
        ok_(self.mgr.parse('mystring >= "hello"')(mystring))
        # inequality reversed
        ok_(self.mgr.parse('"hella" <  mystring')(mystring))
        ok_(self.mgr.parse('"hellz" >  mystring')(mystring))
        ok_(self.mgr.parse('"hellz" >  mystring')(mystring))
        ok_(self.mgr.parse('"hello" >= mystring')(mystring))
        ok_(self.mgr.parse('"hello" >= mystring')(mystring))
        # bool
        ok_(self.mgr.parse('mystring')(mystring))
        ok_(not self.mgr.parse('~ mystring')(mystring))
        ok_(not self.mgr.parse('mystring')({'mystring': ''}))
        ok_(self.mgr.parse('~ mystring')({'mystring': ''}))
        # membership
        ok_(self.mgr.parse('mystring is subset of "zhelloy"')(mystring))
        ok_(not self.mgr.parse('mystring is subset of "zhellai"')(mystring))
        ok_(not self.mgr.parse('mystring is subset of "hello"')(mystring))
        ok_(self.mgr.parse('mystring in "ahelloa"')(mystring))
        ok_(self.mgr.parse('mystring in "hello"')(mystring))
        ok_(not self.mgr.parse('mystring in "hola"')(mystring))
        # inversed membership
        ok_(self.mgr.parse('"he" in mystring')(mystring))
        ok_(self.mgr.parse('"lo" in mystring')(mystring))
        ok_(not self.mgr.parse('"li" in mystring')(mystring))
        ok_(self.mgr.parse('"he" is subset of mystring')(mystring))
        ok_(self.mgr.parse('"lo" is subset of mystring')(mystring))
        ok_(not self.mgr.parse('"li" is subset of mystring')(mystring))
        ok_(not self.mgr.parse(' "hello" is subset of mystring')(mystring))
        # test to string
        ok_(not self.mgr.parse('const:hello is subset of mystring')(mystring))
        ok_(not self.mgr.parse('const:li in mystring')(mystring))

    def test_variable_str(self):
        eq_("%s" % NativeVariable('coucou'),
            'Scop variable for coucou [NativeVariable]')
        eq_("%s" % BooleanVariable('name'),
            'Scop variable for name [BooleanVariable]')
        eq_("%s" % NumberVariable('age'),
            'Scop variable for age [NumberVariable]')

    def test_variable_values_date(self):
        mydate = {
            'mydate': datetime.date(2017, 1, 15),
            'mydate2': datetime.date(2017, 1, 17),
        }
        ok_(self.mgr.parse('mydate')(mydate))

        ok_(self.mgr.parse('mydate < "2017-01-18"')(mydate))
        ok_(self.mgr.parse('mydate < "18-01-2017"')(mydate))
        ok_(not self.mgr.parse('mydate < "12-01-2017"')(mydate))
        ok_(self.mgr.parse('mydate > "12-01-2017"')(mydate))

        ok_(self.mgr.parse('mydate == "15-01-2017"')(mydate))
        ok_(not self.mgr.parse('mydate == 1')(mydate))
        ok_(not self.mgr.parse('mydate == "13-01-2017"')(mydate))
        ok_(self.mgr.parse('mydate < mydate2')(mydate))
        ok_(not self.mgr.parse('mydate > mydate2')(mydate))
        ok_(not self.mgr.parse('mydate == mydate2')(mydate))

    def test_variable_values_datetime(self):
        mydatetime = {
            'mydatetime': datetime.datetime(2017, 1, 15, 12, 25),
            'mydatetime2': datetime.datetime(2017, 1, 17, 12, 23),
        }
        ok_(self.mgr.parse('mydatetime')(mydatetime))

        ok_(self.mgr.parse('mydatetime < "2017-01-15 12:25:02"')(mydatetime))
        ok_(self.mgr.parse('mydatetime > "2017-01-15 12:24:52"')(mydatetime))
        ok_(self.mgr.parse('mydatetime < "2017-01-15 13:00:00"')(mydatetime))
        ok_(self.mgr.parse('mydatetime < "18-01-2017 12:25:02"')(mydatetime))
        ok_(self.mgr.parse('mydatetime < "18-01-2017 12:25:02"')(mydatetime))
        ok_(not self.mgr.parse('mydatetime < "12-01-2017 12:25:02"')
            (mydatetime))
        ok_(self.mgr.parse('mydatetime > "12-01-2017 12:25:02"')(mydatetime))

        ok_(self.mgr.parse('mydatetime == "15-01-2017 12:25:00"')(mydatetime))
        ok_(not self.mgr.parse('mydatetime == 1')(mydatetime))
        ok_(not self.mgr.parse('mydatetime == "13-01-2017 12:25:02"')
            (mydatetime))
        ok_(self.mgr.parse('mydatetime < mydatetime2')(mydatetime))
        ok_(not self.mgr.parse('mydatetime > mydatetime2')(mydatetime))
        ok_(not self.mgr.parse('mydatetime == mydatetime2')(mydatetime))

    def test_variable_values_set(self):
        myset = {
            "myset": {1, 2, 3},
        }
        ok_(self.mgr.parse("1 is subset of myset ")(myset))
        ok_(self.mgr.parse("{1, 2} is subset of myset ")(myset))
        ok_(not self.mgr.parse("{1, 2, 3} is subset of myset ")(myset))
        ok_(self.mgr.parse("1 in myset ")(myset))
        ok_(self.mgr.parse("{1, 2} in myset ")(myset))
        ok_(self.mgr.parse("{1, 2, 3} in myset ")(myset))

    def test_variable_values_namespaced(self):
        myints = {"myint": 1, "sub.myint": 4}
        ok_(self.mgr.parse('sub:myint > 3')(myints))
        ok_(self.mgr.parse('sub:myint < 5')(myints))
        ok_(self.mgr.parse('sub:myint == 4')(myints))
        ok_(self.mgr.parse('sub:myint > myint')(myints))
        ok_(not self.mgr.parse('sub:myint < myint')(myints))
        ok_(not self.mgr.parse('sub:myint == myint')(myints))

    def test_format_date(self):
        dt = DateVariable("mydate", '%d %m %y')
        assert_raises(ValueError, dt._from_native_string, "2001-03-04")
        eq_(dt._from_native_string("04 03 01"), datetime.date(2001, 3, 4))

    def test_multi_formats(self):
        dt = DateVariable("mydate", ['%d %m %Y', '%Y %m %d'])
        assert_raises(ValueError, dt._from_native_string, "2001-03-04")
        assert_raises(ValueError, dt._from_native_string, "04-03-2001")
        eq_(dt._from_native_string("04 03 2001"), datetime.date(2001, 3, 4))
        eq_(dt._from_native_string("2001 03 04"), datetime.date(2001, 3, 4))
示例#13
0
root_table = SymbolTable(
    "root",
    (
        # variablet taken from context
        Bind("age", NumberVariable('age')),
        Bind("name", StringVariable('name')),
        Bind("birthdate", DateVariable("birthdate")),
        Bind("tags", SetVariable("tags")),
        # constants
        Bind("majority", Number(18)),
    ))

# 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,
示例#14
0
    'my_table', [
        Bind('character', name),
    ],
    SymbolTable('character', [
        Bind('age', NumberVariable('age')),
        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'}