def test_global_names(self): """When an operand is bound, its global name must be set accordingly.""" operand = String("hey there") bind1 = Bind("da_global_name", operand) bind2 = Bind("Da_Global_Name", operand) eq_(bind1.global_name, "da_global_name") eq_(bind1.global_name, bind2.global_name)
def test_constructor_with_objects(self): objects = [ Bind("greeting", String("hey")), Bind("traffic", TrafficLightVar()) ] st = SymbolTable("global", objects) eq_(st.objects, set(objects))
def test_retrieving_namespace_with_partially_untrastlated_contents(self): """ When a namespace is requested in a locale in which not all items are available, the namespace with global names should be returned instead. """ bool_var = BoolVar() traffic = TrafficLightVar() st = SymbolTable( "global", (Bind("bool", BoolVar(), es="booleano", fr=u"booléen"), Bind("traffic", TrafficLightVar(), es=u"tráfico")), SymbolTable( "foo", ( Bind("bar", bool_var, es="fulano"), Bind("baz", traffic, es="mengano", fr="bonjour"), ), ), ) # Checking the namespace: namespace = st.get_namespace("fr") eq_(len(namespace.subnamespaces), 1) subnamespace = namespace.subnamespaces["foo"] subnamespace_objects = { 'bar': bool_var, 'bonjour': traffic, } eq_(subnamespace.objects, subnamespace_objects) expected_unbound_objects_global = { u'booléen': BoolVar(), 'traffic': TrafficLightVar(), } eq_(namespace.objects, expected_unbound_objects_global)
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_string_without_symbol_table(self): # With ASCII characters: bind1 = Bind("pi", Number(3.1416)) bind1_as_unicode = six.text_type(bind1) eq_(bind1_as_unicode, 'Operand 3.1416 bound as "pi"') eq_(bind1_as_unicode, six.text_type(bind1)) # With non-ASCII characters: bind2 = Bind(u"pí", Number(3.1416)) bind2_as_unicode = six.text_type(bind2) eq_(bind2_as_unicode, u'Operand 3.1416 bound as "pí"') eq_(six.text_type(bind2), 'Operand 3.1416 bound as "pí"')
def test_checking_duplicate_object_global_names(self): """ Two objects cannot have the same global names in the same table. """ st = SymbolTable( "global", ( Bind("e", Number(2.7183), es_VE=u"número e"), Bind("pi", Number(3.1416)), Bind("e", Number(2.71828), es_ES=u"número e"), ), ) assert_raises(ScopeError, st.validate_scope)
def test_retrieving_non_existing_localized_names(self): """ When a non-existing localized name is requested, a warning must be issued and the global name returned. """ bind = Bind("foo", String("hey"), es="fulano") logging_fixture = LoggingHandlerFixture() eq_(bind.get_localized_name("fr"), "foo") # Checking for the the warning: eq_(len(logging_fixture.handler.messages["warning"]), 1) warning = logging_fixture.handler.messages["warning"][0] eq_(warning, 'Operand "hey" bound as "foo" doesn\'t have a name in fr; ' 'using the global one') # Undoing it: logging_fixture.undo()
def test_string_with_symbol_table(self): # With ASCII characters: bind1 = Bind("pi", Number(3.1416)) SymbolTable("global", [bind1]) bind1_as_unicode = six.text_type(bind1) eq_('Operand 3.1416 bound as "pi" (in Symbol table global)', bind1_as_unicode) eq_(six.text_type(bind1), bind1_as_unicode) # With non-ASCII characters: bind2 = Bind(u"pí", Number(3.1416)) SymbolTable("global", [bind2]) bind2_as_unicode = six.text_type(bind2) eq_(u'Operand 3.1416 bound as "pí" (in Symbol table global)', bind2_as_unicode) eq_('Operand 3.1416 bound as "pí" (in Symbol table global)', six.text_type(bind2))
def test_names(self): """ When an operand is bound, its multiple names must be set accordingly. """ operand = String("Vive la france !") # No localized names: bind1 = Bind("foo", operand) eq_(bind1.names, {}) # Lower-case names: names0 = {'es_VE': "cartuchera", 'es_ES': "estuche"} bind2 = Bind("bar", operand, **names0) eq_(bind2.names, names0) # Mixed-case names -- must be converted to lower-case: names1 = {'es_VE': "Cartuchera", 'es_ES': "estuche"} bind2 = Bind("bar", operand, **names1) eq_(bind2.names, names0)
def test_name_clash_in_grand_children(self): """ The scope must be validated even inside the sub-tables. """ sciences_st1 = SymbolTable( "sciences", (), SymbolTable("maths", (), es=u"matemática"), SymbolTable("computing", ()), SymbolTable("maths", ()), ) sciences_st2 = SymbolTable( "sciences", (), SymbolTable("maths", (), es=u"matemática"), SymbolTable("computing", ()), SymbolTable("mathematics", (), es=u"matemática"), ) sciences_st3 = SymbolTable( "sciences", (), SymbolTable("maths", (), es=u"matemática"), SymbolTable("computing", ()), # This sub-table will be called "matemática" in Spanish too: SymbolTable(u"matemática", ()), ) # Now a name clash at the objects level: sciences_st4 = SymbolTable("global", ( Bind("foo", BoolVar()), Bind("foo", TrafficLightVar(), es="bar"), )) st1 = SymbolTable("global", (), sciences_st1, SymbolTable("society", ())) st2 = SymbolTable("global", (), sciences_st2, SymbolTable("society", ())) st3 = SymbolTable("global", (), sciences_st3, SymbolTable("society", ())) st4 = SymbolTable("global", (), sciences_st4) assert_raises(ScopeError, st1.validate_scope) assert_raises(ScopeError, st2.validate_scope) assert_raises(ScopeError, st3.validate_scope) assert_raises(ScopeError, st4.validate_scope)
def test_checking_valid_table(self): st = SymbolTable( "global", # Bindings/global objects: ( Bind("bool", BoolVar(), es="booleano"), Bind("traffic", TrafficLightVar(), es=u"tráfico"), ), # Sub-tables: SymbolTable( "maths", ( Bind("pi", Number(3.1416)), Bind("e", Number(2.7183)), ), ), ) eq_(st.validate_scope(), None)
def test_checking_object_and_subtable_sharing_localized_name(self): """ It's valid for an object and a sub-table to share the localized name. """ st1 = SymbolTable( "global", (Bind("current_day", BoolVar(), es="hoy"), ), SymbolTable("today", (), es="hoy"), ) st2 = SymbolTable( "global", (Bind("current_day", BoolVar(), es="hoy"), ), # This sub-name will be called "hoy" in Spanish too: SymbolTable("hoy", ()), ) eq_(st1.validate_scope(), None) eq_(st2.validate_scope(), None)
def test_retrieving_non_existing_localized_names(self): """ When a non-existing localized name is requested, a warning must be issued and the global name returned. """ bind = Bind("foo", String("hey"), es="fulano") logging_fixture = LoggingHandlerFixture() eq_(bind.get_localized_name("fr"), "foo") # Checking for the the warning: eq_(len(logging_fixture.handler.messages["warning"]), 1) warning = logging_fixture.handler.messages["warning"][0] eq_( warning, 'Operand "hey" bound as "foo" doesn\'t have a name in fr; ' 'using the global one') # Undoing it: logging_fixture.undo()
def test_checking_object_and_subtable_sharing_global_name(self): """ It's valid for an object and a sub-table to share the global name. """ st = SymbolTable( "global", (Bind("today", BoolVar()), ), SymbolTable("today", ()), ) eq_(st.validate_scope(), None)
def test_retrieving_namespace_without_children(self): """ A namespace shouldn't have sub-namespaces if the original symbol table doesn't have sub-tables. """ bool_var = BoolVar() traffic = TrafficLightVar() st = SymbolTable( "global", (Bind("bool", bool_var, es="booleano"), Bind("traffic", traffic, es=u"tráfico")), ) # Checking the namespace: global_namespace = st.get_namespace() eq_(len(global_namespace.subnamespaces), 0) # Checking the namespace in Castilian: castilian_namespace = st.get_namespace("es") eq_(len(castilian_namespace.subnamespaces), 0)
def test_retrieving_namespace_with_children(self): """ A namespace should have sub-namespaces for the sub-tables of the original symbol table. """ bool_var = BoolVar() traffic = TrafficLightVar() st = SymbolTable( "global", (Bind("bool", bool_var, es="booleano"), Bind("traffic", traffic, es=u"tráfico")), SymbolTable( "foo", ( Bind("bar", bool_var, es="fulano"), Bind("baz", traffic, es="mengano"), ), ), ) # Checking the namespace: global_namespace = st.get_namespace() eq_(len(global_namespace.subnamespaces), 1) global_subnamespace = global_namespace.subnamespaces["foo"] global_subnamespace_objects = { 'bar': bool_var, 'baz': traffic, } eq_(global_subnamespace.objects, global_subnamespace_objects) # Checking the namespace in Castilian: castilian_namespace = st.get_namespace("es") eq_(len(castilian_namespace.subnamespaces), 1) castilian_subnamespace = castilian_namespace.subnamespaces["foo"] castilian_subnamespace_objects = { 'fulano': bool_var, 'mengano': traffic, } eq_(castilian_subnamespace.objects, castilian_subnamespace_objects)
def test_unreusable_bindings(self): """ Operand bindings and symbol tables can only be bound to a single parent symbol table. """ # An operand binding: bind = Bind("traffic-light", TrafficLightVar()) SymbolTable("traffic", [bind]) assert_raises(ScopeError, SymbolTable, "baz", [bind]) # A symbol table: st0 = SymbolTable("foo", []) SymbolTable("global", [], st0) assert_raises(ScopeError, SymbolTable, "bar", [], st0)
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)
def test_duplicate_objects(self): """There must be no duplicate object.""" # In the constructor: objects1 = [ Bind("salutation", String("hey")), Bind("traffic", TrafficLightVar()), Bind("salutation", String("hey")) ] assert_raises(ScopeError, SymbolTable, "global", objects1) # Post-instantiation: objects2 = [ Bind("salutation", String("hey")), Bind("traffic", TrafficLightVar()) ] st = SymbolTable("global", objects2) assert_raises(ScopeError, st.add_object, Bind("salutation", String("hey")))
def test_checking_duplicate_object_localized_names(self): """ Two objects cannot have the same localized names in the same table. """ st1 = SymbolTable( "global", ( Bind("e", Number(2.7183), es_VE=u"número e"), Bind("pi", Number(3.1416)), Bind("eulers-number", Number(2.71828), es_VE=u"número e"), ), ) st2 = SymbolTable( "global", ( Bind("e", Number(2.7183), es_VE=u"número e"), Bind("pi", Number(3.1416)), # These object will be called "número e" in Spanish too: Bind(u"número e", Number(2.71828)), ), ) assert_raises(ScopeError, st1.validate_scope) assert_raises(ScopeError, st2.validate_scope)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import datetime from booleano.operations.operands.constants import Number from booleano.parser.core import EvaluableParseManager from booleano.parser.grammar import Grammar from booleano.operations.variables import NumberVariable, StringVariable, DurationVariable, SetVariable from booleano.parser.scope import SymbolTable, Bind name = StringVariable("name") symbols = SymbolTable( '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
def test_no_default_symbol_table(self): """Operand bindings must not be in a symbol table by default.""" bind = Bind("foo", String("whatever")) eq_(bind.symbol_table, None)
def test_retrieving_existing_localized_names(self): bind = Bind("foo", String("hey"), es="fulano") eq_(bind.get_localized_name("es"), "fulano")
def test_contents_retrieval(self): """Bindings must return bound operand as its contents.""" op = BoolVar() bind = Bind("bool", op) eq_(op, bind._get_contents(None))
def test_constant(self): """Constants can be bound.""" constant = String("I'm a string!") bound_constant = Bind("da_string", constant) eq_(bound_constant.operand, constant)
def test_equivalence(self): objects1 = lambda: [ Bind("dish", String("cachapa")), Bind("drink", String("empanada")) ] objects2 = lambda: [ Bind("drink", String("empanada")), Bind("dish", String("cachapa")) ] objects3 = lambda: [Bind("pi", Number(3.1416))] st1 = SymbolTable("foo", objects1()) st2 = SymbolTable("foo", objects1()) st3 = SymbolTable("foo", objects1(), es="fulano") st4 = SymbolTable("foo", objects1(), es="fulano") st5 = SymbolTable("foo", objects2()) st6 = SymbolTable("foo", objects3()) st7 = SymbolTable("foo", objects2(), es="fulano") st8 = SymbolTable("foo", objects3(), es_VE="fulano") st9 = SymbolTable("bar", objects1()) st10 = SymbolTable("foo", objects1()) st11 = SymbolTable("foo", objects1(), SymbolTable("bar", []), SymbolTable("baz", [])) st12 = SymbolTable("foo", objects1(), SymbolTable("baz", []), SymbolTable("bar", [])) # Moving st10 into the "baz" symbol table: SymbolTable("baz", [], st10) ok_(st1 == st2) ok_(st1 == st5) ok_(st1 == st10) ok_(st2 == st1) ok_(st2 == st5) ok_(st2 == st10) ok_(st3 == st4) ok_(st3 == st7) ok_(st4 == st3) ok_(st4 == st7) ok_(st5 == st1) ok_(st5 == st2) ok_(st5 == st10) ok_(st7 == st3) ok_(st7 == st4) ok_(st10 == st1) ok_(st10 == st2) ok_(st10 == st5) ok_(st11 == st12) ok_(st12 == st11) ok_(st1 != None) ok_(st1 != Bind("foo", String("cachapa"))) ok_(st1 != st3) ok_(st1 != st4) ok_(st1 != st6) ok_(st1 != st7) ok_(st1 != st8) ok_(st1 != st9) ok_(st1 != st11) ok_(st1 != st12) ok_(st2 != st3) ok_(st2 != st4) ok_(st2 != st6) ok_(st2 != st7) ok_(st2 != st8) ok_(st2 != st9) ok_(st2 != st11) ok_(st2 != st12) ok_(st3 != st1) ok_(st3 != st2) ok_(st3 != st5) ok_(st3 != st6) ok_(st3 != st8) ok_(st3 != st9) ok_(st3 != st10) ok_(st3 != st11) ok_(st3 != st12) ok_(st4 != st1) ok_(st4 != st2) ok_(st4 != st5) ok_(st4 != st6) ok_(st4 != st8) ok_(st4 != st9) ok_(st4 != st10) ok_(st4 != st11) ok_(st4 != st12) ok_(st5 != st3) ok_(st5 != st4) ok_(st5 != st6) ok_(st5 != st7) ok_(st5 != st8) ok_(st5 != st9) ok_(st5 != st11) ok_(st5 != st12) ok_(st6 != st1) ok_(st6 != st2) ok_(st6 != st3) ok_(st6 != st4) ok_(st6 != st5) ok_(st6 != st7) ok_(st6 != st8) ok_(st6 != st9) ok_(st6 != st10) ok_(st6 != st11) ok_(st6 != st12) ok_(st7 != st1) ok_(st7 != st2) ok_(st7 != st5) ok_(st7 != st6) ok_(st7 != st8) ok_(st7 != st9) ok_(st7 != st10) ok_(st7 != st11) ok_(st7 != st12) ok_(st8 != st1) ok_(st8 != st2) ok_(st8 != st3) ok_(st8 != st4) ok_(st8 != st5) ok_(st8 != st6) ok_(st8 != st7) ok_(st8 != st9) ok_(st8 != st10) ok_(st8 != st11) ok_(st8 != st12) ok_(st9 != st1) ok_(st9 != st2) ok_(st9 != st3) ok_(st9 != st4) ok_(st9 != st5) ok_(st9 != st6) ok_(st9 != st7) ok_(st9 != st8) ok_(st9 != st10) ok_(st9 != st11) ok_(st9 != st12) ok_(st10 != st3) ok_(st10 != st4) ok_(st10 != st6) ok_(st10 != st7) ok_(st10 != st8) ok_(st10 != st9) ok_(st11 != st1) ok_(st11 != st2) ok_(st11 != st3) ok_(st11 != st4) ok_(st11 != st5) ok_(st11 != st6) ok_(st11 != st7) ok_(st11 != st8) ok_(st11 != st9) ok_(st11 != st10) ok_(st12 != st1) ok_(st12 != st2) ok_(st12 != st3) ok_(st12 != st4) ok_(st12 != st5) ok_(st12 != st6) ok_(st12 != st7) ok_(st12 != st8) ok_(st12 != st9) ok_(st12 != st10)
def test_instance(self): """Class instances can be bound.""" instance = TrafficLightVar() bound_instance = Bind("da_variable", instance) eq_(bound_instance.operand, instance)
def test_equality(self): """Two bindings are equivalent if they have the same names.""" op1 = TrafficLightVar() op2 = String("hey, where's my car?") bind1 = Bind("name1", op1) bind2 = Bind("name2", op2) bind3 = Bind("name2", op1) bind4 = Bind("name1", op2) bind5 = Bind("name1", op1) bind6 = Bind("name2", op2) bind7 = Bind("name1", op1, es="nombre1") bind8 = Bind("name1", op1, es_VE="nombre1", es="nombre1") bind9 = Bind("name1", op1, es="nombre1") ok_(bind1 == bind4) ok_(bind1 == bind5) ok_(bind2 == bind3) ok_(bind2 == bind6) ok_(bind3 == bind2) ok_(bind3 == bind6) ok_(bind4 == bind1) ok_(bind4 == bind5) ok_(bind5 == bind5) ok_(bind5 == bind1) ok_(bind5 == bind4) ok_(bind6 == bind2) ok_(bind6 == bind3) ok_(bind7 == bind9) ok_(bind9 == bind7) ok_(bind1 != None) ok_(bind1 != SymbolTable("name1", [])) ok_(bind1 != bind2) ok_(bind1 != bind3) ok_(bind1 != bind6) ok_(bind1 != bind7) ok_(bind1 != bind8) ok_(bind1 != bind9) ok_(bind2 != bind1) ok_(bind2 != bind4) ok_(bind2 != bind5) ok_(bind2 != bind7) ok_(bind2 != bind8) ok_(bind2 != bind9) ok_(bind3 != bind1) ok_(bind3 != bind4) ok_(bind3 != bind5) ok_(bind3 != bind7) ok_(bind3 != bind8) ok_(bind3 != bind9) ok_(bind4 != bind2) ok_(bind4 != bind3) ok_(bind4 != bind6) ok_(bind4 != bind7) ok_(bind4 != bind8) ok_(bind4 != bind9) ok_(bind5 != bind2) ok_(bind5 != bind3) ok_(bind5 != bind6) ok_(bind5 != bind7) ok_(bind5 != bind8) ok_(bind5 != bind9) ok_(bind6 != bind1) ok_(bind6 != bind4) ok_(bind6 != bind5) ok_(bind6 != bind7) ok_(bind6 != bind8) ok_(bind6 != bind9) ok_(bind7 != bind1) ok_(bind7 != bind2) ok_(bind7 != bind3) ok_(bind7 != bind4) ok_(bind7 != bind5) ok_(bind7 != bind6) ok_(bind7 != bind8) ok_(bind8 != bind1) ok_(bind8 != bind2) ok_(bind8 != bind3) ok_(bind8 != bind4) ok_(bind8 != bind5) ok_(bind8 != bind6) ok_(bind8 != bind7) ok_(bind8 != bind9) ok_(bind9 != bind1) ok_(bind9 != bind2) ok_(bind9 != bind3) ok_(bind9 != bind4) ok_(bind9 != bind5) ok_(bind9 != bind6) ok_(bind9 != bind8)
def test_repr(self): bind = Bind("pi", Number(3.1416)) eq_(repr(bind), u'<Operand 3.1416 bound as "pi">')
"age": 16, "birthdate": datetime.date(1983, 1, 1) }, { "name": "sokka", "age": 15, "birthdate": datetime.date(1984, 1, 1) }, ] # 1: create a static Symbol Table 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