Esempio n. 1
0
    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)
Esempio n. 2
0
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), (), {})
Esempio n. 3
0
  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)
Esempio n. 4
0
    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)
Esempio n. 5
0
  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()
Esempio n. 6
0
    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")
Esempio n. 7
0
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),
                         (), {})
Esempio n. 8
0
    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)
Esempio n. 9
0
    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)
Esempio n. 10
0
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)))
Esempio n. 11
0
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")
Esempio n. 12
0
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)))
Esempio n. 13
0
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)
Esempio n. 14
0
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")
Esempio n. 15
0
 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
Esempio n. 16
0
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)
Esempio n. 17
0
 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
Esempio n. 18
0
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
Esempio n. 19
0
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
Esempio n. 20
0
    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)
Esempio n. 21
0
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)
Esempio n. 22
0
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)
Esempio n. 23
0
  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)
Esempio n. 24
0
  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)
Esempio n. 25
0
  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")
Esempio n. 26
0
def fullEval(val, env):
    p = partialEval(val, env)
    return p.v
Esempio n. 27
0
    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)
Esempio n. 28
0
def jmap(iterable, mapper):
  iterable = partialEval(fexpr_cast(iterable))
  return jmap2(iterable, mapper)
Esempio n. 29
0
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)
Esempio n. 30
0
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)
Esempio n. 31
0
def fullEval(val, env):
  p = partialEval(val, env)
  return p.v
Esempio n. 32
0
  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)