def __init__(self, *args, **kwargs): """ An object just responsible for Keeping overlord queries and doing some serialization stuff if any ... """ #some initialization stuff here ... fact_query = None if kwargs.has_key('fact_query'): fact_query = kwargs['fact_query'] self.fact_query = fact_query or FuncLogicQuery()
def deserialize(self, q_list): """ Method gets the lists that is sent from overlord (pure string or list) and converts into a FuncLogicQuery so facts can be pulled from prewritten modules... @type q_list : list @param q_list : Query list """ q_result = self.__traverse_deserialize(q_list) if not self.fact_query: self.fact_query = FuncLogicQuery(q_result, self.pull_facts) else: if self.fact_query.q.connector == "OR": self.fact_query = self.fact_query | FuncLogicQuery( q_result, self.pull_facts) else: self.fact_query = self.fact_query & FuncLogicQuery( q_result, self.pull_facts) return q_result
def deserialize(self,q_list): """ Method gets the lists that is sent from overlord (pure string or list) and converts into a FuncLogicQuery so facts can be pulled from prewritten modules... @type q_list : list @param q_list : Query list """ q_result = self.__traverse_deserialize(q_list) if not self.fact_query: self.fact_query = FuncLogicQuery(q_result,self.pull_facts) else: if self.fact_query.q.connector == "OR": self.fact_query = self.fact_query | FuncLogicQuery(q_result,self.pull_facts) else: self.fact_query = self.fact_query & FuncLogicQuery(q_result,self.pull_facts) return q_result
class FactsMinion(object): """ That class wil be responsible for: 1. De-serialization of the query by converting it to a Q structure. 2. Calling the ( prewritten ) 'facts' modules """ VALID_QUERY_KEYS = ["AND", "OR", "NOT"] def __init__(self, fact_query=None, method_fact_list=None): """ Constructor @type fact_query : FuncLogicQuery @param fact_query : FuncLogicQuery that will be produced from that class if not given from constructor as it is here. @type method_fact_list : list @param method_fact_list : List of prewritten 'facts' modules you can find them under facts/modules directory @return : None """ self.fact_query = fact_query self.keyword_query = QueryKeyword() self.method_fact_list = method_fact_list def deserialize(self, q_list): """ Method gets the lists that is sent from overlord (pure string or list) and converts into a FuncLogicQuery so facts can be pulled from prewritten modules... @type q_list : list @param q_list : Query list """ q_result = self.__traverse_deserialize(q_list) if not self.fact_query: self.fact_query = FuncLogicQuery(q_result, self.pull_facts) else: if self.fact_query.q.connector == "OR": self.fact_query = self.fact_query | FuncLogicQuery( q_result, self.pull_facts) else: self.fact_query = self.fact_query & FuncLogicQuery( q_result, self.pull_facts) return q_result def exec_query(self, q_list, include_results=False): """ The magic method which gives the final result of that query with values in it if requested. That is why we have include_results sometimes. @type q_list : list @param q_list : Query list @type include_results : boolean @param include_results : As it is known the main purpose of facts is to return True or False but sometimes we need the real result also included. """ self.deserialize(q_list) if not include_results: return self.fact_query.result else: return self.fact_query.exec_query_with_facts() def pull_facts(self, overlord_tuple): """ Pull facts is kind of callback method which is called by FuncLogicQuery when does the logic query operation in its recursive traversing ... That way we dont put all the pulling operations in FuncLogicQuery but making it pluggable by calling from outside. That is the place where we actually call the 'fact' modules. If you need change in calling fact methods that is the place to go . @type overlord_tuple : Tuple @param overlord_tuple : A tuple in format of (factname__factoperation,compared_value) """ keyword_tuple = overlord_tuple[0].split("__") overlord_value = overlord_tuple[1] if len(keyword_tuple) > 1: keyword = keyword_tuple[1] else: keyword = "" fact_name = keyword_tuple[0] if not self.method_fact_list.has_key(fact_name): raise MinionQueryError( "None existing Fact method or tag required %s " % fact_name) fact_value = self.method_fact_list[fact_name]() #we have the result with fact now it is time to resolve it logic_fact = self.keyword_query.resolve(keyword, overlord_value, fact_value) #the return part is a tuple (logic_Value which is True or False and fact_name and value dictionary ) return (logic_fact, {fact_name: fact_value}) def __traverse_deserialize(self, traverse_object): """ The private recursive part that traverses the incoming overlord list (included with facts) and produces a Q object query object from it. **(heavy recursive code)Caution any change here can make facts not tobe deserialized correctly so that will break the facts API. @type : list @param : List of overlord incoming facts query something like :[NOT,[AND,[a,TRUE,b,FALSE]]] @return : Q object returned """ q_object = None #lets try divide and conquer :) #assume that it is [NOT,[AND,[a,TRUE,b,FALSE]]] #print "The traverse object at start is ",traverse_object tmp_negated = False tmp_connector = "AND" if type(traverse_object[0]) == str and traverse_object[0] == "NOT": tmp_negated = True #q_object.negated = ~q_object traverse_object = traverse_object[1:][0] #print "After NOT the traverse_object is ",traverse_object #raw_input() if type(traverse_object[0]) == str and traverse_object[0] in [ "AND", "OR" ]: #q_object.connector = traverse_object[0] tmp_connector = traverse_object[0] traverse_object = traverse_object[1:][0] #print "After CONNETOR the traverse_object is ",traverse_object #raw_input() if type(traverse_object[0] ) == str and not traverse_object[0] in self.VALID_QUERY_KEYS: #print "In children : ",traverse_object for ch in xrange(0, len(traverse_object), 2): #q_object.add(Q(tuple(traverse_object[ch:ch+2])),q_object.connector) #print "We work on ",traverse_object[ch:ch+2] if not q_object: q_object = Q(tuple(traverse_object[ch:ch + 2])) q_object.connector = tmp_connector else: if q_object.connector == "OR": q_object = q_object | Q( tuple(traverse_object[ch:ch + 2])) else: q_object = q_object & Q( tuple(traverse_object[ch:ch + 2])) if tmp_negated: q_object = ~q_object #print "IN children Q object is ",q_object traverse_object = [] #print "After CHILDREN the traverse_object is ",traverse_object #raw_input() if traverse_object: #print "The traverse object at end is ",traverse_object #raw_input() for t_o in traverse_object: #print "The traverse object at end is ",t_o #raw_input() tmp_q = self.__traverse_deserialize(t_o) #print "I ADD THAT TO THE ALL ",tmp_q #print "WILL BE ADDED TO ",q_object if not q_object: q_object = Q() q_object.connector = tmp_connector #q_object.add(tmp_q,q_object.connector) if tmp_connector == "OR": q_object = q_object | tmp_q else: q_object = q_object & tmp_q #print "AFTER ADDITION ",q_object if tmp_negated: q_object = ~q_object return q_object
class FactsMinion(object): """ That class wil be responsible for: 1. De-serialization of the query by converting it to a Q structure. 2. Calling the ( prewritten ) 'facts' modules """ VALID_QUERY_KEYS = ["AND","OR","NOT"] def __init__(self,fact_query=None,method_fact_list=None): """ Constructor @type fact_query : FuncLogicQuery @param fact_query : FuncLogicQuery that will be produced from that class if not given from constructor as it is here. @type method_fact_list : list @param method_fact_list : List of prewritten 'facts' modules you can find them under facts/modules directory @return : None """ self.fact_query = fact_query self.keyword_query = QueryKeyword() self.method_fact_list = method_fact_list def deserialize(self,q_list): """ Method gets the lists that is sent from overlord (pure string or list) and converts into a FuncLogicQuery so facts can be pulled from prewritten modules... @type q_list : list @param q_list : Query list """ q_result = self.__traverse_deserialize(q_list) if not self.fact_query: self.fact_query = FuncLogicQuery(q_result,self.pull_facts) else: if self.fact_query.q.connector == "OR": self.fact_query = self.fact_query | FuncLogicQuery(q_result,self.pull_facts) else: self.fact_query = self.fact_query & FuncLogicQuery(q_result,self.pull_facts) return q_result def exec_query(self,q_list,include_results=False): """ The magic method which gives the final result of that query with values in it if requested. That is why we have include_results sometimes. @type q_list : list @param q_list : Query list @type include_results : boolean @param include_results : As it is known the main purpose of facts is to return True or False but sometimes we need the real result also included. """ self.deserialize(q_list) if not include_results: return self.fact_query.result else: return self.fact_query.exec_query_with_facts() def pull_facts(self,overlord_tuple): """ Pull facts is kind of callback method which is called by FuncLogicQuery when does the logic query operation in its recursive traversing ... That way we dont put all the pulling operations in FuncLogicQuery but making it pluggable by calling from outside. That is the place where we actually call the 'fact' modules. If you need change in calling fact methods that is the place to go . @type overlord_tuple : Tuple @param overlord_tuple : A tuple in format of (factname__factoperation,compared_value) """ keyword_tuple = overlord_tuple[0].split("__") overlord_value = overlord_tuple[1] if len(keyword_tuple) > 1: keyword = keyword_tuple[1] else: keyword = "" fact_name = keyword_tuple[0] if not self.method_fact_list.has_key(fact_name): raise MinionQueryError("None existing Fact method or tag required %s "%fact_name) fact_value = self.method_fact_list[fact_name]() #we have the result with fact now it is time to resolve it logic_fact = self.keyword_query.resolve(keyword,overlord_value,fact_value) #the return part is a tuple (logic_Value which is True or False and fact_name and value dictionary ) return (logic_fact,{fact_name:fact_value}) def __traverse_deserialize(self,traverse_object): """ The private recursive part that traverses the incoming overlord list (included with facts) and produces a Q object query object from it. **(heavy recursive code)Caution any change here can make facts not tobe deserialized correctly so that will break the facts API. @type : list @param : List of overlord incoming facts query something like :[NOT,[AND,[a,TRUE,b,FALSE]]] @return : Q object returned """ q_object = None #lets try divide and conquer :) #assume that it is [NOT,[AND,[a,TRUE,b,FALSE]]] #print "The traverse object at start is ",traverse_object tmp_negated = False tmp_connector ="AND" if type(traverse_object[0]) == str and traverse_object[0] == "NOT": tmp_negated = True #q_object.negated = ~q_object traverse_object = traverse_object[1:][0] #print "After NOT the traverse_object is ",traverse_object #raw_input() if type(traverse_object[0]) == str and traverse_object[0] in ["AND","OR"]: #q_object.connector = traverse_object[0] tmp_connector = traverse_object[0] traverse_object = traverse_object[1:][0] #print "After CONNETOR the traverse_object is ",traverse_object #raw_input() if type(traverse_object[0])==str and not traverse_object[0] in self.VALID_QUERY_KEYS: #print "In children : ",traverse_object for ch in xrange(0,len(traverse_object),2): #q_object.add(Q(tuple(traverse_object[ch:ch+2])),q_object.connector) #print "We work on ",traverse_object[ch:ch+2] if not q_object: q_object = Q(tuple(traverse_object[ch:ch+2])) q_object.connector = tmp_connector else: if q_object.connector == "OR": q_object = q_object | Q(tuple(traverse_object[ch:ch+2])) else: q_object = q_object & Q(tuple(traverse_object[ch:ch+2])) if tmp_negated: q_object = ~q_object #print "IN children Q object is ",q_object traverse_object = [] #print "After CHILDREN the traverse_object is ",traverse_object #raw_input() if traverse_object: #print "The traverse object at end is ",traverse_object #raw_input() for t_o in traverse_object: #print "The traverse object at end is ",t_o #raw_input() tmp_q = self.__traverse_deserialize(t_o) #print "I ADD THAT TO THE ALL ",tmp_q #print "WILL BE ADDED TO ",q_object if not q_object: q_object = Q() q_object.connector = tmp_connector #q_object.add(tmp_q,q_object.connector) if tmp_connector== "OR": q_object = q_object | tmp_q else: q_object = q_object & tmp_q #print "AFTER ADDITION ",q_object if tmp_negated: q_object = ~q_object return q_object
def setUp(self): self.q1 = FuncLogicQuery(Q(a=True, b=True)) self.q2 = FuncLogicQuery(Q(a=False, b=True)) self.q3 = FuncLogicQuery(Q(a=True, b=False)) self.q4 = FuncLogicQuery(Q(a=False, b=False)) self.q_negated = FuncLogicQuery(~Q(a=False, b=False))
class TestFactsTree(object): def setUp(self): self.q1 = FuncLogicQuery(Q(a=True, b=True)) self.q2 = FuncLogicQuery(Q(a=False, b=True)) self.q3 = FuncLogicQuery(Q(a=True, b=False)) self.q4 = FuncLogicQuery(Q(a=False, b=False)) self.q_negated = FuncLogicQuery(~Q(a=False, b=False)) def test_print_facts_tree(self): """ You will see those only with -s option of nosetests """ #print q.children #print q print self.q1 print self.q2 print self.q3 print self.q4 print self.q_negated def test_traverse_logic_tree(self): assert self.q1.result == True assert self.q2.result == False assert self.q3.result == False assert self.q4.result == False assert self.q_negated.result == True q1_q2_or = self.q3 | self.q1 q1_q2_and = self.q1 & self.q2 assert q1_q2_or.result == True assert q1_q2_and.result == False tmp = q1_q2_or | q1_q2_and tmp2 = q1_q2_or & q1_q2_and assert tmp.result == True assert tmp2.result == False #lets do sth more more complex :) very_tmp = tmp & tmp very_tmp2 = tmp2 | tmp2 & tmp assert very_tmp.result == True assert very_tmp2.result == False def test_filter(self): """ Do some testing on filtering the stuff """ tmp_q = self.q1.filter(c=False, e=True) assert tmp_q.result == False tmp_q = self.q1.filter(c=True, e=True) assert tmp_q.result == True tmp_q = self.q2.filter(c=False, e=True) assert tmp_q.result == False tmp_q = self.q3.filter(c=False, e=True) assert tmp_q.result == False tmp_q = self.q4.filter(c=False, e=True) assert tmp_q.result == False def test_exclude(self): """ Test the negated situations """ tmp_q = self.q1.exclude(c=False, e=True) assert tmp_q.result == True def test_complex(self): """ The complex thing """ #what it does is creates a Q on the #fly and ORs it with set_compexq tmp_q = self.q1.set_compexq((Q(a=True, b=True) | Q(c=False, d=True)), "OR") assert tmp_q.result == True tmp_q = self.q1.set_compexq((Q(a=True, b=False) | Q(c=False, d=False)), "AND") assert tmp_q.result == False
def setUp(self): self.q1 = FuncLogicQuery(Q(a=True,b=True)) self.q2 = FuncLogicQuery(Q(a=False,b=True)) self.q3 = FuncLogicQuery(Q(a=True,b=False)) self.q4 = FuncLogicQuery(Q(a=False,b=False)) self.q_negated = FuncLogicQuery(~Q(a=False,b=False))
class TestFactsTree(object): def setUp(self): self.q1 = FuncLogicQuery(Q(a=True,b=True)) self.q2 = FuncLogicQuery(Q(a=False,b=True)) self.q3 = FuncLogicQuery(Q(a=True,b=False)) self.q4 = FuncLogicQuery(Q(a=False,b=False)) self.q_negated = FuncLogicQuery(~Q(a=False,b=False)) def test_print_facts_tree(self): """ You will see those only with -s option of nosetests """ #print q.children #print q print self.q1 print self.q2 print self.q3 print self.q4 print self.q_negated def test_traverse_logic_tree(self): assert self.q1.result == True assert self.q2.result == False assert self.q3.result == False assert self.q4.result == False assert self.q_negated.result == True q1_q2_or = self.q3 | self.q1 q1_q2_and = self.q1 & self.q2 assert q1_q2_or.result == True assert q1_q2_and.result == False tmp = q1_q2_or | q1_q2_and tmp2 = q1_q2_or & q1_q2_and assert tmp.result == True assert tmp2.result == False #lets do sth more more complex :) very_tmp = tmp & tmp very_tmp2 = tmp2 | tmp2 & tmp assert very_tmp.result == True assert very_tmp2.result == False def test_filter(self): """ Do some testing on filtering the stuff """ tmp_q = self.q1.filter(c=False,e=True) assert tmp_q.result == False tmp_q = self.q1.filter(c=True,e=True) assert tmp_q.result == True tmp_q=self.q2.filter(c=False,e=True) assert tmp_q.result == False tmp_q=self.q3.filter(c=False,e=True) assert tmp_q.result == False tmp_q=self.q4.filter(c=False,e=True) assert tmp_q.result == False def test_exclude(self): """ Test the negated situations """ tmp_q = self.q1.exclude(c=False,e=True) assert tmp_q.result == True def test_complex(self): """ The complex thing """ #what it does is creates a Q on the #fly and ORs it with set_compexq tmp_q=self.q1.set_compexq( (Q(a=True,b=True)| Q(c=False,d=True)), "OR" ) assert tmp_q.result == True tmp_q=self.q1.set_compexq( (Q(a=True,b=False)| Q(c=False,d=False)), "AND" ) assert tmp_q.result == False