def testPartialEval(self): JeevesLib.init() l = Var("l") a = Facet(l, Constant(1), Constant(2)) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l: True}), 1) self.assertEqual(ap.eval({l: False}), 2) a = Facet(l, Add(Constant(1), Constant(-1)), Constant(2)) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l: True}), 0) self.assertEqual(ap.eval({l: False}), 2) a = Add(Facet(l, Constant(1), Constant(10)), Facet(l, Constant(100), Constant(1000))) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l: True}), 101) self.assertEqual(ap.eval({l: False}), 1010) l1 = Var("l1") l2 = Var("l2") a = Add(Facet(l1, Constant(1), Constant(10)), Facet(l2, Constant(100), Constant(1000))) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l1: True, l2: True}), 101) self.assertEqual(ap.eval({l1: True, l2: False}), 1001) self.assertEqual(ap.eval({l1: False, l2: True}), 110) self.assertEqual(ap.eval({l1: False, l2: False}), 1010)
def jfun(f, *args, **kw): if hasattr(f, '__jeeves'): return f(*args, **kw) else: env = jeevesState.pathenv.getEnv() if len(args) > 0: return jfun2(f, args, kw, 0, partialEval(fexpr_cast(args[0]), env), []) else: it = kw.__iter__() try: fst = next(it) except StopIteration: return fexpr_cast(f()) return jfun3(f, kw, it, fst, partialEval(fexpr_cast(kw[fst]), env), (), {})
def delete(self, *args, **kw): if self.jeeves_id is None: return field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) all_vars = [] d = {} env = JeevesLib.jeevesState.pathenv.getEnv() for field_name in field_names: value = getattr(self, field_name) f = partialEval(fexpr_cast(value), env) all_vars.extend(v.name for v in f.vars()) d[field_name] = f for p in powerset(all_vars): true_vars = list(p) false_vars = list(set(all_vars).difference(p)) e = dict(env) e.update({tv : True for tv in true_vars}) e.update({fv : False for fv in false_vars}) self.do_delete(e)
def delete(self, *args, **kw): if self.jeeves_id is None: return field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) all_vars = [] d = {} env = JeevesLib.jeevesState.pathenv.getEnv() for field_name in field_names: value = getattr(self, field_name) f = partialEval(fexpr_cast(value), env) all_vars.extend(v.name for v in f.vars()) d[field_name] = f for p in powerset(all_vars): true_vars = list(p) false_vars = list(set(all_vars).difference(p)) e = dict(env) e.update({tv: True for tv in true_vars}) e.update({fv: False for fv in false_vars}) self.do_delete(e)
def delete(self, *args, **kw): if self.jeeves_id is None: return field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) all_vars = [] d = {} env = JeevesLib.jeevesState.pathenv.getEnv() for field_name in field_names: value = getattr(self, field_name) f = partialEval(fexpr_cast(value), env) all_vars.extend(v.name for v in f.vars()) d[field_name] = f for p in powerset(all_vars): true_vars = list(p) false_vars = list(set(all_vars).difference(p)) e = dict(env) e.update({tv : True for tv in true_vars}) e.update({fv : False for fv in false_vars}) delete_query = self.__class__._objects_ordinary.filter(jeeves_id=self.jeeves_id) for var_name, var_value in e: delete_query = delete_query.filter(jeeves_vars__contains = ';%s=%d;' % (var_name, var_value)) delete_query.delete()
def get(self, use_base_env=False, **kwargs): l = self.filter(**kwargs).get_jiter() if len(l) == 0: return None for (o, _) in l: if o.jeeves_id != l[0][0].jeeves_id: raise Exception( "wow such error: get() found rows for more than one jeeves_id" ) cur = None for (o, conditions) in l: old = cur cur = FObject(o) for var_name, val in conditions.iteritems(): if val: cur = Facet( acquire_label_by_name(self.model._meta.app_label, var_name), cur, old) else: cur = Facet( acquire_label_by_name(self.model._meta.app_label, var_name), old, cur) try: return partialEval( cur, {} if use_base_env else JeevesLib.jeevesState.pathenv.getEnv()) except TypeError: raise Exception( "wow such error: could not find a row for every condition")
def concretizeExp(self, f, pathenv): f = fast.AST.fexpr_cast(f) while self.policies_index < len(self.policies): label, policy = self.policies[self.policies_index] self.policies_index += 1 predicate = policy(self.ctxt) #predicate should be True if label can be HIGH predicate_vars = predicate.vars() constraint = partialEval(fast.AST.Implies(label, predicate), pathenv) if constraint.type != bool: raise ValueError("constraints must be bools") self.solver.boolExprAssert(constraint) if not self.solver.check(): raise UnsatisfiableException("Constraints not satisfiable") vars_needed = f.vars() for var in vars_needed: if var not in self.result: self.solver.push() self.solver.boolExprAssert(var) if self.solver.isSatisfiable(): self.result[var] = True else: self.solver.pop() self.solver.boolExprAssert(fast.AST.Not(var)) self.result[var] = False assert self.solver.check() return f.eval(self.result)
def concretizeExp(self, f, pathenv): f = fast.AST.fexpr_cast(f) while self.policies_index < len(self.policies): label, policy = self.policies[self.policies_index] self.policies_index += 1 predicate = policy( self.ctxt) #predicate should be True if label can be HIGH predicate_vars = predicate.vars() constraint = partialEval(fast.AST.Implies(label, predicate), pathenv) if constraint.type != bool: raise ValueError("constraints must be bools") self.solver.boolExprAssert(constraint) if not self.solver.check(): raise UnsatisfiableException("Constraints not satisfiable") vars_needed = f.vars() for var in vars_needed: if var not in self.result: self.solver.push() self.solver.boolExprAssert(var) if self.solver.isSatisfiable(): self.result[var] = True else: self.solver.pop() self.solver.boolExprAssert(fast.AST.Not(var)) self.result[var] = False assert self.solver.check() return f.eval(self.result)
def jmap(iterable, mapper): if isinstance(iterable, JList2): return jmap_jlist2(iterable, mapper) if isinstance(iterable, FObject) and isinstance(iterable.v, JList2): return jmap_jlist2(iterable.v, mapper) iterable = partialEval(fexpr_cast(iterable), jeevesState.pathenv.getEnv()) return FObject(JList(jmap2(iterable, mapper)))
def evalToConcrete(f): g = partialEval(fexpr_cast(f), jeevesState.pathenv.getEnv()) if isinstance(g, Constant): return g.v elif isinstance(g, FObject): return g.v else: raise Exception("wow such error: evalToConcrete on non-concrete thingy-ma-bob")
def jfun2(f, args, kw, i, arg, args_concrete): if isinstance(arg, Constant) or isinstance(arg, FObject): env = jeevesState.pathenv.getEnv() if i < len(args) - 1: return jfun2(f, args, kw, i+1, partialEval(fexpr_cast(args[i+1]), env), tuple(list(args_concrete) + [arg.v])) else: it = kw.__iter__() try: fst = next(it) except StopIteration: return fexpr_cast(f(*tuple(list(args_concrete) + [arg.v]))) return jfun3(f, kw, it, fst, partialEval(fexpr_cast(kw[fst]), env), tuple(list(args_concrete) + [arg.v]), {}) else: with PositiveVariable(arg.cond): thn = jfun2(f, args, kw, i, arg.thn, args_concrete) with NegativeVariable(arg.cond): els = jfun2(f, args, kw, i, arg.els, args_concrete) return Facet(arg.cond, thn, els)
def evalToConcrete(f): g = partialEval(fexpr_cast(f), jeevesState.pathenv.getEnv()) if isinstance(g, Constant): return g.v elif isinstance(g, FObject): return g.v else: raise Exception( "wow such error: evalToConcrete on non-concrete thingy-ma-bob")
def applyInputWP(self, writer, writeCtxt): if self.inputWP: r = self.inputWP(self.v)(writer) if isinstance(r, FExpr): r = JeevesLib.concretize(writeCtxt, partialEval(r, JeevesLib.jeevesState.pathenv.getEnv())) if r: return UpdateResult.Success else: return UpdateResult.Failure else: return UpdateResult.Success
def jfun2(f, args, kw, i, arg, args_concrete): if isinstance(arg, Constant) or isinstance(arg, FObject): env = jeevesState.pathenv.getEnv() if i < len(args) - 1: return jfun2(f, args, kw, i + 1, partialEval(fexpr_cast(args[i + 1]), env), tuple(list(args_concrete) + [arg.v])) else: it = kw.__iter__() try: fst = next(it) except StopIteration: return fexpr_cast(f(*tuple(list(args_concrete) + [arg.v]))) return jfun3(f, kw, it, fst, partialEval(fexpr_cast(kw[fst]), env), tuple(list(args_concrete) + [arg.v]), {}) else: with PositiveVariable(arg.cond): thn = jfun2(f, args, kw, i, arg.thn, args_concrete) with NegativeVariable(arg.cond): els = jfun2(f, args, kw, i, arg.els, args_concrete) return Facet(arg.cond, thn, els)
def applyInputWP(self, writer, writeCtxt): if self.inputWP: r = self.inputWP(self.v)(writer) if isinstance(r, FExpr): r = JeevesLib.concretize( writeCtxt, partialEval(r, JeevesLib.jeevesState.pathenv.getEnv())) if r: return UpdateResult.Success else: return UpdateResult.Failure else: return UpdateResult.Success
def jassign(old, new, base_env={}): res = new for vs in jeevesState.pathenv.conditions: (var, val) = (vs.var, vs.val) if var.name not in base_env: if val: res = Facet(var, res, old) else: res = Facet(var, old, res) if isinstance(res, FExpr): return partialEval(res, {}, True) else: return res
def testPartialEval(self): JeevesLib.init() l = Var("l") a = Facet(l, Constant(1), Constant(2)) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l:True}), 1) self.assertEqual(ap.eval({l:False}), 2) a = Facet(l, Add(Constant(1), Constant(-1)), Constant(2)) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l:True}), 0) self.assertEqual(ap.eval({l:False}), 2) a = Add( Facet(l, Constant(1), Constant(10)), Facet(l, Constant(100), Constant(1000)) ) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l:True}), 101) self.assertEqual(ap.eval({l:False}), 1010) l1 = Var("l1") l2 = Var("l2") a = Add( Facet(l1, Constant(1), Constant(10)), Facet(l2, Constant(100), Constant(1000)) ) ap = partialEval(a) self.assertTrue(isPureFacetTree(ap)) self.assertEqual(ap.eval({l1:True, l2:True}), 101) self.assertEqual(ap.eval({l1:True, l2:False}), 1001) self.assertEqual(ap.eval({l1:False, l2:True}), 110) self.assertEqual(ap.eval({l1:False, l2:False}), 1010)
def jfun3(f, kw, it, key, val, args_concrete, kw_concrete): if isinstance(val, Constant) or isinstance(val, FObject): kw_c = dict(kw_concrete) kw_c[key] = val.v try: next_key = next(it) except StopIteration: return fexpr_cast(f(*args_concrete, **kw_c)) env = jeevesState.pathenv.getEnv() return jfun3(f, kw, it, next_key, partialEval(fexpr_cast(kw[next_key]), env), args_concrete, kw_c) else: with PositiveVariable(val.cond): thn = jfun3(f, kw, it, key, val.thn, args_concrete, kw_concrete) with NegativeVariable(val.cond): els = jfun3(f, kw, it, key, val.els, args_concrete, kw_concrete) return Facet(arg.cond, thn, els)
def jfun3(f, kw, it, key, val, args_concrete, kw_concrete): if isinstance(val, Constant) or isinstance(val, FObject): kw_c = dict(kw_concrete) kw_c[key] = val.v try: next_key = next(it) except StopIteration: return fexpr_cast(f(*args_concrete, **kw_c)) env = jeevesState.pathenv.getEnv() return jfun3(f, kw, it, next_key, partialEval(fexpr_cast(kw[next_key]), env), args_concrete, kw_c) else: it1, it2 = tee(it) with PositiveVariable(val.cond): thn = jfun3(f, kw, it1, key, val.thn, args_concrete, kw_concrete) with NegativeVariable(val.cond): els = jfun3(f, kw, it2, key, val.els, args_concrete, kw_concrete) return Facet(val.cond, thn, els)
def concretizeExp(self, ctxt, f): f = fast.AST.fexpr_cast(f) dependencies = defaultdict(set) constraints = [] # First, find all all the dependencies between labels # and add Not(predicate) ==> label == LOW conditions for (label, policy) in self.policies.iteritems(): predicate = policy(ctxt) #predicate should be True if label can be HIGH predicate_vars = predicate.vars() dependencies[label] |= predicate_vars constraints.append(partialEval(fast.AST.Implies(label, predicate))) # If a depends on b, then we want (b == Low ==> a == Low) for (label, label_deps) in dependencies.iteritems(): for label_dep in label_deps: constraints.append(fast.AST.Implies(label, label_dep)) env = smt.SMT.solve(constraints, self.labels[::-1], f.vars()) return f.eval(env)
def save(self, *args, **kw): if not self.jeeves_id: self.jeeves_id = get_random_jeeves_id() if kw.get("update_field", None) is not None: raise NotImplementedError("Partial saves not supported.") field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) all_vars = [] d = {} env = JeevesLib.jeevesState.pathenv.getEnv() for field_name in field_names: value = getattr(self, field_name) f = partialEval(fexpr_cast(value), env) all_vars.extend(v.name for v in f.vars()) d[field_name] = f for p in powerset(all_vars): true_vars = list(p) false_vars = list(set(all_vars).difference(p)) e = dict(env) e.update({tv : True for tv in true_vars}) e.update({fv : False for fv in false_vars}) delete_query = self.__class__._objects_ordinary.filter(jeeves_id=self.jeeves_id) for var_name, var_value in e: delete_query = delete_query.filter(jeeves_vars__contains = ';%s=%d;' % (var_name, var_value)) delete_query.delete() klass = self.__class__ obj_to_save = klass(**{ field_name : fullEval(field_value, env) for field_name, field_value in d.iteritems() }) obj_to_save.jeeves_vars = serialize_vars(e) super(JeevesModel, obj_to_save).save(*args, **kw)
def get(self, use_base_env=False, **kwargs): l = self.filter(**kwargs).get_jiter() if len(l) == 0: return None for (o, _) in l: if o.jeeves_id != l[0][0].jeeves_id: raise Exception("wow such error: get() found rows for more than one jeeves_id") cur = None for (o, conditions) in l: old = cur cur = FObject(o) for var_name, val in conditions.iteritems(): if val: cur = Facet(acquire_label_by_name(self.model._meta.app_label, var_name), cur, old) else: cur = Facet(acquire_label_by_name(self.model._meta.app_label, var_name), old, cur) try: return partialEval(cur, {} if use_base_env else JeevesLib.jeevesState.pathenv.getEnv()) except TypeError: raise Exception("wow such error: could not find a row for every condition")
def fullEval(val, env): p = partialEval(val, env) return p.v
def save(self, *args, **kw): if not self.jeeves_id: self.jeeves_id = get_random_jeeves_id() if kw.get("update_field", None) is not None: raise NotImplementedError("Partial saves not supported.") field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) for label_name, field_name_list in self._jeeves_labels.iteritems(): label = self.acquire_label(label_name) for field_name in field_name_list: public_field_value = getattr(self, field_name) private_field_value = getattr( self, 'jeeves_get_private_' + field_name)(self) faceted_field_value = partialEval( JeevesLib.mkSensitive(label, public_field_value, private_field_value), JeevesLib.jeevesState.pathenv.getEnv()) setattr(self, field_name, faceted_field_value) all_vars = [] d = {} env = JeevesLib.jeevesState.pathenv.getEnv() for field_name in field_names: value = getattr(self, field_name) f = partialEval(fexpr_cast(value), env) all_vars.extend(v.name for v in f.vars()) d[field_name] = f all_vars = list(set(all_vars)) for p in powerset(all_vars): true_vars = list(p) false_vars = list(set(all_vars).difference(p)) e = dict(env) e.update({tv: True for tv in true_vars}) e.update({fv: False for fv in false_vars}) self.do_delete(e) klass = self.__class__ obj_to_save = klass( **{ field_name: fullEval(field_value, e) for field_name, field_value in d.iteritems() }) all_jid_objs = list( klass._objects_ordinary.filter( jeeves_id=obj_to_save.jeeves_id).all()) all_relevant_objs = [ obj for obj in all_jid_objs if all(field_name == 'jeeves_vars' or getattr( obj_to_save, field_name) == getattr(obj, field_name) for field_name in d) ] while True: # check if we can collapse # if we can, repeat; otherwise, exit for i in xrange(len(all_relevant_objs)): other_obj = all_relevant_objs[i] diff_var = get_one_differing_var( e, unserialize_vars(other_obj.jeeves_vars)) if diff_var is not None: super(JeevesModel, other_obj).delete() del e[diff_var] break else: break obj_to_save.jeeves_vars = serialize_vars(e) super(JeevesModel, obj_to_save).save(*args, **kw)
def jmap(iterable, mapper): iterable = partialEval(fexpr_cast(iterable)) return jmap2(iterable, mapper)
def jif(cond, thn_fn, els_fn): condTrans = partialEval(fexpr_cast(cond), jeevesState.pathenv.getEnv()) if condTrans.type != bool: raise TypeError("jif must take a boolean as a condition") return jif2(condTrans, thn_fn, els_fn)
def save(self, *args, **kw): if not self.jeeves_id: self.jeeves_id = get_random_jeeves_id() if kw.get("update_field", None) is not None: raise NotImplementedError("Partial saves not supported.") field_names = set() for field in self._meta.concrete_fields: if not field.primary_key and not hasattr(field, 'through'): field_names.add(field.attname) for label_name, field_name_list in self._jeeves_labels.iteritems(): label = self.acquire_label(label_name) for field_name in field_name_list: public_field_value = getattr(self, field_name) private_field_value = getattr(self, 'jeeves_get_private_' + field_name)(self) faceted_field_value = partialEval( JeevesLib.mkSensitive(label, public_field_value, private_field_value), JeevesLib.jeevesState.pathenv.getEnv() ) setattr(self, field_name, faceted_field_value) all_vars = [] d = {} env = JeevesLib.jeevesState.pathenv.getEnv() for field_name in field_names: value = getattr(self, field_name) f = partialEval(fexpr_cast(value), env) all_vars.extend(v.name for v in f.vars()) d[field_name] = f all_vars = list(set(all_vars)) for p in powerset(all_vars): true_vars = list(p) false_vars = list(set(all_vars).difference(p)) e = dict(env) e.update({tv : True for tv in true_vars}) e.update({fv : False for fv in false_vars}) self.do_delete(e) klass = self.__class__ obj_to_save = klass(**{ field_name : fullEval(field_value, e) for field_name, field_value in d.iteritems() }) all_jid_objs = list(klass._objects_ordinary.filter(jeeves_id=obj_to_save.jeeves_id).all()) all_relevant_objs = [obj for obj in all_jid_objs if all(field_name == 'jeeves_vars' or getattr(obj_to_save, field_name) == getattr(obj, field_name) for field_name in d)] while True: # check if we can collapse # if we can, repeat; otherwise, exit for i in xrange(len(all_relevant_objs)): other_obj = all_relevant_objs[i] diff_var = get_one_differing_var(e, unserialize_vars(other_obj.jeeves_vars)) if diff_var is not None: super(JeevesModel, other_obj).delete() del e[diff_var] break else: break obj_to_save.jeeves_vars = serialize_vars(e) super(JeevesModel, obj_to_save).save(*args, **kw)