Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

Changeset 41

Show
Ignore:
Timestamp:
12/20/04 21:43:48
Author:
fumanchu
Message:

1. codewalk.EarlyBinder? now late-binds any object with a bind_late attribute which evaluates to True. Notice that functions are first-class objects and so may be assigned such an attribute.
2. Changed postgres timedelta from pg interval to float8.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/codewalk.py

    r40 r41  
    9696                          if k not in ('BINARY_SUBSCR',) 
    9797                          ]) 
    98 del k, v 
    9998 
    10099binary_repr = {'BINARY_POWER': '**', 
     
    132131                  'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 
    133132                  'co_stacksize', 'co_varnames'] 
     133 
    134134 
    135135class Visitor(object): 
     
    425425     
    426426    def pop(self, index=-1): 
    427         """Returns a tuple!! of (value, tainted).""" 
     427        """pop(index) -> Returns a tuple!! of (value, tainted).""" 
    428428        if index < 0: 
    429429            index += len(self) 
     
    441441 
    442442class EarlyBinder(Rewriter): 
    443     """EarlyBinder(func, reduce_getattr=True, taintlist=[]) 
     443    """EarlyBinder(func, reduce_getattr=True, bind_late=[]) 
    444444     
    445445    Deep-evaluate function, replacing free vars with constants. 
     
    448448        replaced with x.y where possible. 
    449449     
    450     taintlist: a list of names (globals, freevars, or attributes) 
     450    bind_late: a list of names (globals, freevars, or attributes) 
    451451        which should not be early-bound. For example, if you want 
    452452        datetime.date.today() to be bound late, include 'today' 
    453         in the taintlist
     453        in the bind_late
    454454     
    455455    Example: k = lambda x: x.Date == datetime.date(2004, 1, 1) 
     
    483483    """ 
    484484     
    485     def __init__(self, func, reduce_getattr=True, taintlist=[]): 
     485    def __init__(self, func, reduce_getattr=True, bind_late=[]): 
    486486        Rewriter.__init__(self, func) 
    487487        self.reduce_getattr = reduce_getattr 
     
    498498        # This stack is not passed out of this class in any way. 
    499499        self.stack = TaintableStack() 
    500         self.taintlist = taintlist 
     500        self.bind_late = bind_late 
    501501     
    502502    def code_object(self): 
     
    530530     
    531531    def reduce(self, number_of_terms, transform=None, overwrite_length=None): 
    532         """If no stack args are tainted, rewrite previous opcodes. 
     532        """If no stack args are to be bound late, rewrite previous opcodes. 
    533533         
    534534        number_of_terms: the number of terms to pop off the stack. 
     
    560560            # tainted, because CALL_FUNCTION will do it normally. 
    561561            if self.reduce_getattr: 
    562                 if (len(terms) == 3 
    563                     and terms[2] == getattr 
    564                     and taints[1] 
    565                     and not taints[0]): 
    566                         # Form a new LOAD_ATTR instruction. 
    567                         pos = self.name_index(terms[0]) 
    568                         # Unlike normal CALL_FUNCTION, we can't 
    569                         # assume each arg is a constant; therefore, 
    570                         # our overwrite_length is indeterminate. 
    571                         # We'll just cheat and keep track of the last 
    572                         # LOAD_GLOBAL where we looked up getattr. ;) 
    573                         start = self.last_getattr 
    574                         # Grab and reuse opcodes of first (LOAD_FAST) term. 
    575                         bits = self.newcode[start + 3:-6] 
    576                         bits += ['LOAD_ATTR', pos & 0xFF, pos >> 8] 
    577                         bits = tuple(bits) 
    578                         self.put(start, len(self.newcode), *bits) 
    579                         self.stack.append(None) 
    580                         self.stack.taint() 
    581                         return True 
     562                if (len(terms) == 3 and terms[2] == getattr 
     563                    and taints[1] and not taints[0]): 
     564                    # Form a new LOAD_ATTR instruction. 
     565                    pos = self.name_index(terms[0]) 
     566                    # Unlike normal CALL_FUNCTION, we can't assume each arg 
     567                    # is a constant; therefore, our overwrite_length is 
     568                    # indeterminate. We'll just cheat and keep track of 
     569                    # the last LOAD_GLOBAL where we looked up getattr. ;) 
     570                    start = self.last_getattr 
     571                    # Grab and reuse opcodes of first (LOAD_FAST) term. 
     572                    bits = self.newcode[start + 3:-6] 
     573                    bits += ['LOAD_ATTR', pos & 0xFF, pos >> 8] 
     574                    bits = tuple(bits) 
     575                    self.put(start, len(self.newcode), *bits) 
     576                    self.stack.append(None) 
     577                    self.stack.taint() 
     578                    return None 
    582579             
    583580            # Don't form the new object. 
     
    585582            self.stack.append(None) 
    586583            self.stack.taint() 
    587             return Fals
     584            return Non
    588585         
    589586        # Callback the transform. 
     
    600597        pos = self.const_index(result) 
    601598        self.tail(overwrite_length, 'LOAD_CONST', pos & 0xFF, pos >> 8) 
    602         return True 
     599         
     600        return result 
    603601     
    604602    def visit_BUILD_TUPLE(self, lo, hi): 
     
    627625    def visit_LOAD_ATTR(self, lo, hi): 
    628626        name = self.co_names[lo + (hi << 8)] 
    629         self.reduce(1, lambda terms: getattr(terms[0], name)) 
    630         if name in self.taintlist
     627        result = self.reduce(1, lambda terms: getattr(terms[0], name)) 
     628        if result in self.bind_late or getattr(result, 'bind_late', False)
    631629            self.stack.taint() 
    632630     
     
    642640            self.tail(3, 'LOAD_CONST', pos & 0xFF, pos >> 8) 
    643641            self.stack.append(value) 
    644             if name in self.taintlist
     642            if value in self.bind_late or getattr(value, 'bind_late', False)
    645643                self.stack.taint() 
    646644     
    647645    def visit_LOAD_FAST(self, lo, hi): 
    648646        self.stack.append(self.co_varnames[lo + (hi << 8)]) 
     647        # LOAD_FAST references our bound variable, which is always bound late. 
    649648        self.stack.taint() 
    650649     
     
    658657            self.tail(3, 'LOAD_CONST', pos & 0xFF, pos >> 8) 
    659658            self.stack.append(value) 
    660             if name in self.taintlist
     659            if value in self.bind_late or getattr(value, 'bind_late', False)
    661660                self.stack.taint() 
    662661        else: 
     
    681680 
    682681# Add visit_BINARY, visit_INPLACE methods to EarlyBinder. 
    683 for key, opd in binary_operators.iteritems(): 
    684     setattr(EarlyBinder, "visit_" + key
    685             lambda self, opr=opd: self.binary_op(opr)) 
    686 for key, opd in inplace_operators.iteritems(): 
    687     setattr(EarlyBinder, "visit_" + key
     682for k, v in binary_operators.iteritems(): 
     683    setattr(EarlyBinder, "visit_" + k
     684            lambda self, opr=v: self.binary_op(opr)) 
     685for k, v in inplace_operators.iteritems(): 
     686    setattr(EarlyBinder, "visit_" + k
    688687            # Yes, we really do call binary_op for inplace methods. 
    689             lambda self, opr=opd: self.binary_op(opr)) 
    690 del key, opd 
     688            lambda self, opr=v: self.binary_op(opr)) 
    691689 
    692690 
     
    886884 
    887885# Add visit_BINARY methods to LambdaDecompiler. 
    888 for key, op in binary_repr.iteritems(): 
    889     setattr(LambdaDecompiler, "visit_" + key
    890             lambda self, op=op: self.binary_op(op)) 
     886for k, v in binary_repr.iteritems(): 
     887    setattr(LambdaDecompiler, "visit_" + k
     888            lambda self, op=v: self.binary_op(op)) 
    891889 
    892890 
     
    964962            self.flag = None 
    965963 
     964del k, v 
     965 
  • trunk/logic.py

    r40 r41  
    234234    def _load_func(self, func): 
    235235        # Early-bind as much as possible. 
    236         binder = codewalk.EarlyBinder(func, taintlist=['now', 'today', 
    237                                                        'iscurrentweek']) 
     236        binder = codewalk.EarlyBinder(func, bind_late=[datetime.datetime.now, datetime.date.today]) 
    238237        self.func = binder.function() 
    239238     
  • trunk/storage/storepypgsql.py

    r40 r41  
    471471    def coerce_datetime_date(self, cls, key): return u"date" 
    472472    def coerce_datetime_time(self, cls, key): return u"time" 
    473     def coerce_datetime_timedelta(self, cls, key): return u"interval" 
     473     
     474    def coerce_datetime_timedelta(self, cls, key): 
     475        # I was seriously disinterested in writing a parser for interval. 
     476        return u"float8" 
     477     
    474478    def coerce_decimal(self, cls, key): return u"numeric" 
    475479     
  • trunk/test_codewalk.py

    r40 r41  
    147147        # Test a tainted (late-bound) function 
    148148        e = lambda x: x.FirstDate >= datetime.date.today() 
    149         r = codewalk.EarlyBinder(e, taintlist=['today']).bytecode() 
     149        r = codewalk.EarlyBinder(e, bind_late=[datetime.date.today]).bytecode() 
    150150        self.assertEqual(r, nums(['LOAD_FAST', 0, 0, 
    151151                                  'LOAD_ATTR', 1, 0,