class _ClassDelegate(classy): """Type whose attributes/methods are delegated to ``cls.get()``""" __slots__ = () get = None # dummy decorate(classmethod) def __class_init__(cls, name, bases, cdict, supr): meta = type(cls) if getattr(meta, '__for_class__', None) is not cls: cls.__class__ = meta = type(meta)(cls.__name__ + 'Class', (meta, ), dict(_std_attrs, __module__=cls.__module__, __for_class__=cls)) # XXX activate_attrs(meta)? supr()(cls, name, bases, cdict, supr) if 'get' not in cdict: cls.get = staticmethod(classmethod(lookup).__get__(None, cls)) for k, v in cdict.items(): if not isinstance(k, basestring): continue if not isinstance(v, (classmethod, staticmethod)) and not _ignore(k): redirect_attribute(cls, k, v)
class MethodList(Method): """A list of related methods""" can_tail = False _sorted_items = None def __init__(self, items=(), tail=None): self.items = list(items) self.tail = tail decorate(classmethod) def make(cls, body, signature=(), serial=0): return cls( [(serial, signature, body)] ) def __repr__(self): data = self.items, self.tail return self.__class__.__name__+repr(data) def tail_with(self, tail): return self.__class__(self.items, tail) def merge(self, other): if other.__class__ is not self.__class__: raise TypeError("Incompatible action types for merge", self, other) return self.__class__( self.items+other.items, combine_actions(self.tail, other.tail) ) def compiled(self, engine): wrappers = tuple(engine.rules.methodlist_wrappers) bodies = [compile_method(body,engine) for sig, body in self.sorted()] return engine.apply_template(list_template, tuple(bodies), wrappers) def sorted(self): if self._sorted_items is not None: return self._sorted_items self.items.sort() rest = [(s,b) for (serial, s, b) in self.items] self._sorted_items = items = [] seen = set() while rest: best = dominant_signatures(rest) list(map(rest.remove, best)) for s,b in best: if b not in seen: seen.add(b) items.append((s,b)) return items
class State(_ClassDelegate): """A thread's current configuration and state""" def __new__(cls, *rules, **attrs): return attrs and object.__new__(cls) or empty() def __init__(self, **attrs): """Create an empty state with `rules` in effect""" self.__dict__.update(attrs) def __getitem__(self, key): """Get the rule for `key`""" return self.getRule(key) def __setitem__(self, key, rule): """Set the rule for `key`""" return self.setRule(key, rule) def swap(self): """Make this state current and return the old one""" raise NotImplementedError("Can't switch to the root state") def child(self, *rules): """Return a new child state of this one, with `rules` in effect""" raise NotImplementedError # this method is replaced on each instance def __enter__(self): """Make this state a single-use nested state""" raise NotImplementedError("Can't enter the root state") def __exit__(self, typ, val, tb): """Close this state and invoke exit callbacks""" raise NotImplementedError("Can't exit the root state") def on_exit(self, callback): """Add a `callback(typ,val,tb)` to be invoked at ``__exit__`` time""" raise NotImplementedError # this method is replaced on each instance decorate(staticmethod) def get(key=None): """Return the current state (no args) or a current rule (w/key)""" # this method is replaced later below raise NotImplementedError parent = None
for ob in args: if callable(ob): last = ob(self) else: try: f = generate_types[type(ob)] except KeyError: raise TypeError("Can't generate", ob) else: last = f(self, ob) return last def return_(self, ob=None): return self(ob, Code.RETURN_VALUE) decorate(classmethod) def from_function(cls, function, copy_lineno=False): code = cls.from_code(function.func_code, copy_lineno) return code decorate(classmethod) def from_code(cls, code, copy_lineno=False): import inspect self = cls.from_spec(code.co_name, *inspect.getargs(code)) if copy_lineno: self.set_lineno(code.co_firstlineno) self.co_filename = code.co_filename self.co_freevars = code.co_freevars # XXX untested!
# unit tests... if __name__ == "__main__": logging.basicConfig(level=logging.WARNING, format='%(name)s %(levelname)s %(filename)s, %(funcName)s, Line: %(lineno)d: %(message)s',) log = getLog("foobar.bubble") root = getLog(name="") log.setLevel(logging.WARNING) root.setLevel(logging.DEBUG) log.debug(" --> debug") log.error(" --> error") log.warning(" --> warning") log.warn(" --> warn") decorate(traceLog(log)) def testFunc(arg1, arg2="default", *args, **kargs): return 42 testFunc("hello", "world", logger=root) testFunc("happy", "joy", name="skippy") testFunc("hi") decorate(traceLog(root)) def testFunc22(): return testFunc("archie", "bunker") testFunc22() decorate(traceLog(root)) def testGen():
class BitmapIndex(AddOn): """Index that computes selectivity and handles basic caching w/bitmaps""" known_cases = 0 match = True, decorate(staticmethod) def addon_key(*args): # Always use BitmapIndex as the add-on key return (BitmapIndex, ) + args def __new__(cls, engine, expr): if cls is BitmapIndex: cls = bitmap_index_type(engine, expr) return super(BitmapIndex, cls).__new__(cls) def __init__(self, engine, expr): self.extra = {} self.null = self.all_seeds = {} # seed -> inc_cri, exc_cri self.criteria_bits = {} # cri -> case bits self.case_seeds = [] # case -> seed set self.criteria_seeds = {} # cri -> seeds def add_case(self, case_id, criterion): if criterion in self.criteria_seeds: seeds = self.criteria_seeds[criterion] else: self.criteria_bits.setdefault(criterion, 0) seeds = self.criteria_seeds[criterion] = self.add_criterion( criterion) case_seeds = self.case_seeds if case_id == len(case_seeds): case_seeds.append(seeds) else: self._extend_cases(case_id) case_seeds[case_id] = seeds bit = to_bits([case_id]) self.known_cases |= bit self.criteria_bits[criterion] |= bit def add_criterion(self, criterion): """Ensure `criterion` is indexed, return its "applicable seeds" set As a side effect, ``self.all_seeds`` must be updated to include any new seeds required by `criterion`. """ raise NotImplementedError def _extend_cases(self, case_id): if case_id >= len(self.case_seeds): self.case_seeds.extend([self.null] * (case_id + 1 - len(self.case_seeds))) def selectivity(self, cases): if cases and cases[-1] >= len(self.case_seeds): self._extend_cases(cases[-1]) cases = list(map(self.case_seeds.__getitem__, cases)) return (len(self.all_seeds), sum(map(len, cases))) def seed_bits(self, cases): bits = self.criteria_bits return cases ^ (self.known_cases & cases), dict([ (seed, (sum([bits[i] for i in inc]) & cases, sum([bits[e] for e in exc]) & cases)) for seed, (inc, exc) in self.all_seeds.items() ]) def expanded_sets(self): return [(seed, [list(from_bits(inc)), list(from_bits(exc))]) for seed, (inc, exc) in self.seed_bits(self.known_cases)[1].items()] def reseed(self, criterion): self.add_criterion(criterion) def include(self, seed, criterion, exclude=False): try: s = self.all_seeds[seed] except KeyError: s = self.all_seeds[seed] = set(), set() s[exclude].add(criterion) self.criteria_bits.setdefault(criterion, 0) def exclude(self, seed, criterion): self.include(seed, criterion, True)
# unit tests... if __name__ == "__main__": logging.basicConfig( level=logging.WARNING, format= '%(name)s %(levelname)s %(filename)s, %(funcName)s, Line: %(lineno)d: %(message)s', ) log = getLog("foobar.bubble") root = getLog(name="") log.setLevel(logging.WARNING) root.setLevel(logging.DEBUG) log.debug(" --> debug") log.error(" --> error") decorate(traceLog(log)) def testFunc(arg1, arg2="default", *args, **kargs): return 42 testFunc("hello", "world", logger=root) testFunc("happy", "joy", name="skippy") testFunc("hi") decorate(traceLog(root)) def testFunc22(): return testFunc("archie", "bunker") testFunc22()
class Method(with_metaclass(MethodType)): """A simple method w/optional chaining""" def __init__(self, body, signature=(), serial=0, tail=None): self.body = body self.signature = signature self.serial = serial self.tail = tail self.can_tail = False try: args = inspect.getargspec(body)[0] except TypeError: pass else: if args and args[0]=='next_method': if getattr(body, 'im_self', None) is None: # already bound? self.can_tail = True decorate(classmethod) def make(cls, body, signature=(), serial=0): return cls(body, signature, serial) def __repr__(self): data = (self.body, self.signature, self.serial, self.tail) return self.__class__.__name__+repr(data) def __call__(self, *args, **kw): """Slow way to call a method -- use compile_method instead!""" return compile_method(self)(*args, **kw) def override(self, other): if not self.can_tail: return self return self.tail_with(combine_actions(self.tail, other)) def tail_with(self, tail): return self.__class__(self.body, self.signature, self.serial, tail) def merge(self, other): #if self.__class__ is other.__class__ and self.body is other.body: # XXX need to merge signatures? # return self.__class__( # self.body, ???, ???, combine_actions(self.tail, other.tail) # ) return AmbiguousMethods([self,other]) decorate(classmethod) def make_decorator(cls, name, doc=None): if doc is None: doc = "Extend a generic function with a method of type ``%s``" \ % cls.__name__ if cls is Method: maker = None # allow gf's to use something else instead of Method else: maker = cls.make def decorate(f, pred=(), depth=2, frame=None): def callback(frame, name, func, old_locals): assert f is not func # XXX kind, module, locals_, globals_ = frameinfo(frame) context = ParseContext(func, maker, locals_, globals_, lineno) def register_for_class(cls, f=f): _register_rule(f, pred, context, cls) return cls if kind=='class': # 'when()' in class body; defer adding the method decorate_class(register_for_class, frame=frame) else: register_for_class(None) if old_locals.get(name) is f: return f # prevent overwriting if name is the same return func rv = decorate_assignment(callback, depth, frame) if frame is None: frame = sys._getframe(depth-1) lineno = frame.f_lineno # this isn't valid w/out active trace! return rv decorate = with_name(decorate, name) decorate.__doc__ = doc return decorate def compiled(self, engine): body = compile_method(self.body, engine) if not self.can_tail: return body else: return types.MethodType(body, compile_method(self.tail, engine))
class Code(object): co_argcount = 0 co_stacksize = 0 co_flags = CO_OPTIMIZED | CO_NEWLOCALS # typical usage co_filename = '<generated code>' co_name = '<lambda>' co_firstlineno = 0 co_freevars = () co_cellvars = () _last_lineofs = 0 _last_line = 0 _ss = 0 _tmp_level = 0 def __init__(self): self.co_code = array('B') self.co_consts = [None] self.co_names = [] self.co_varnames = [] self.co_lnotab = array('B') self.emit = self.co_code.append self.blocks = [] self.stack_history = [] def emit_arg(self, op, arg): emit = self.emit if arg>0xFFFF: emit(EXTENDED_ARG) emit((arg>>16)&255) emit((arg>>24)&255) emit(op) emit(arg&255) emit((arg>>8)&255) def locals_written(self): vn = self.co_varnames hl = dict.fromkeys([STORE_FAST, DELETE_FAST]) return dict.fromkeys([vn[arg] for ofs, op, arg in self if op in hl]) def set_lineno(self, lno): if not self.co_firstlineno: self.co_firstlineno = self._last_line = lno return append = self.co_lnotab.append incr_line = lno - self._last_line incr_addr = len(self.co_code) - self._last_lineofs if not incr_line: return if incr_addr<=0 or incr_line<=0: return while incr_addr>255: append(255) append(0) incr_addr -= 255 while incr_line>255: append(incr_addr) append(255) incr_line -= 255 incr_addr = 0 if incr_addr or incr_line: append(incr_addr) append(incr_line) self._last_line = lno self._last_lineofs = len(self.co_code) def YIELD_VALUE(self): self.stackchange(stack_effects[YIELD_VALUE]) self.co_flags |= CO_GENERATOR return self.emit(YIELD_VALUE) def LOAD_CONST(self, const): self.stackchange((0,1)) pos = 0 hashable = True try: hash(const) except TypeError: hashable = False while 1: try: arg = self.co_consts.index(const, pos) it = self.co_consts[arg] except ValueError: arg = len(self.co_consts) self.co_consts.append(const) break else: if type(it) is type(const) and (hashable or it is const): break pos = arg+1 continue return self.emit_arg(LOAD_CONST, arg) def CALL_FUNCTION(self, argc=0, kwargc=0, op=CALL_FUNCTION, extra=0): self.stackchange((1+argc+2*kwargc+extra,1)) emit = self.emit emit(op); emit(argc); emit(kwargc) def CALL_FUNCTION_VAR(self, argc=0, kwargc=0): self.CALL_FUNCTION(argc,kwargc,CALL_FUNCTION_VAR, 1) # 1 for *args def CALL_FUNCTION_KW(self, argc=0, kwargc=0): self.CALL_FUNCTION(argc,kwargc,CALL_FUNCTION_KW, 1) # 1 for **kw def CALL_FUNCTION_VAR_KW(self, argc=0, kwargc=0): self.CALL_FUNCTION(argc,kwargc,CALL_FUNCTION_VAR_KW, 2) # 2 *args,**kw def BUILD_TUPLE(self, count): self.stackchange((count,1)) self.emit_arg(BUILD_TUPLE,count) def BUILD_LIST(self, count): self.stackchange((count,1)) self.emit_arg(BUILD_LIST,count) def UNPACK_SEQUENCE(self, count): self.stackchange((1,count)) self.emit_arg(UNPACK_SEQUENCE,count) def RETURN_VALUE(self): self.stackchange((1,0)) self.emit(RETURN_VALUE) self.stack_unknown() def BUILD_SLICE(self, count): assert count in (2,3), "Invalid number of arguments for BUILD_SLICE" self.stackchange((count,1)) self.emit_arg(BUILD_SLICE,count) def DUP_TOPX(self, count): self.stackchange((count,count*2)) self.emit_arg(DUP_TOPX,count) def RAISE_VARARGS(self, argc): assert 0<=argc<=3, "Invalid number of arguments for RAISE_VARARGS" self.stackchange((argc,0)) self.emit_arg(RAISE_VARARGS,argc) def MAKE_FUNCTION(self, ndefaults): self.stackchange((1+ndefaults,1)) self.emit_arg(MAKE_FUNCTION, ndefaults) def MAKE_CLOSURE(self, ndefaults, freevars): if sys.version>='2.5': freevars = 1 self.stackchange((1+freevars+ndefaults,1)) self.emit_arg(MAKE_CLOSURE, ndefaults) def here(self): return len(self.co_code) if 'UNARY_CONVERT' not in opcode: def UNARY_CONVERT(self): self(Const(repr)) self.ROT_TWO() self.CALL_FUNCTION(1, 0) if 'BINARY_DIVIDE' not in opcode: def BINARY_DIVIDE(self): self.BINARY_TRUE_DIVIDE() if 'DUP_TOPX' not in opcode: def DUP_TOPX(self, count): self.stackchange((count,count*2)) if count==2: self.emit(DUP_TOP_TWO) else: raise RuntimeError("Python 3 only supports DUP_TOP_TWO") if 'SLICE_0' not in opcode: def SLICE_0(self): self(None, None, Code.SLICE_3) def SLICE_1(self): self(None, Code.SLICE_3) def SLICE_2(self): self(None, Code.ROT_TWO, Code.SLICE_3) def SLICE_3(self): self.BUILD_SLICE(2) self.BINARY_SUBSCR() def set_stack_size(self, size): if size<0: raise AssertionError("Stack underflow") if size>self.co_stacksize: self.co_stacksize = size bytes = len(self.co_code) - len(self.stack_history) + 1 if bytes>0: self.stack_history.extend([self._ss]*bytes) self._ss = size def get_stack_size(self): return self._ss stack_size = property(get_stack_size, set_stack_size) def stackchange(self, inout): (inputs,outputs) = inout if self._ss is None: raise AssertionError("Unknown stack size at this location") self.stack_size -= inputs # check underflow self.stack_size += outputs # update maximum height def stack_unknown(self): self._ss = None def branch_stack(self, location, expected): if location >= len(self.stack_history): if location > len(self.co_code): raise AssertionError("Forward-looking stack prediction!", location, len(self.co_code) ) actual = self.stack_size if actual is None: self.stack_size = actual = expected self.stack_history[location] = actual else: actual = self.stack_history[location] if actual is None: self.stack_history[location] = actual = expected if actual != expected: raise AssertionError( "Stack level mismatch: actual=%s expected=%s" % (actual, expected) ) def jump(self, op, arg=None): def jump_target(offset): target = offset #print op #print hasjabs if op not in hasjabs: target = target - (posn+3) if target<0: raise AssertionError("Relative jumps can't go backwards") if True: target = offset - (posn+6) return target def backpatch(offset): target = jump_target(offset) #if target>0xFFFF: # print hasjabs # print hasjrel # print op # print "ofs: " + hex(offset) + ", tgt: " + hex(target) + ", posn: " + hex(posn) #exit(0) #raise AssertionError("Forward jump span must be <64K bytes") assert(op!=120) self.patch_arg(posn, 0x1FFFF, target,op) self.branch_stack(offset, old_level) if op==FOR_ITER: old_level = self.stack_size = self.stack_size - 1 self.stack_size += 2 else: old_level = self.stack_size self.stack_size -= (op in (JUMP_IF_TRUE_OR_POP, JUMP_IF_FALSE_OR_POP)) posn = self.here() if arg is not None: print "jt: " + hex(jump_target(arg)) self.emit_arg(op, jump_target(arg)) self.branch_stack(arg, old_level) lbl = None else: self.emit_arg(op, 0x1FFFF) def lbl(code=None): backpatch(self.here()) if op in (JUMP_FORWARD, JUMP_ABSOLUTE, CONTINUE_LOOP): self.stack_unknown() return lbl def COMPARE_OP(self, op): self.stackchange((2,1)) self.emit_arg(COMPARE_OP, compares[op]) def setup_block(self, op): jmp = self.jump(op) self.blocks.append((op,self.stack_size,jmp)) return jmp def SETUP_EXCEPT(self): ss = self.stack_size self.stack_size = ss+3 # simulate the level at "except:" time self.setup_block(SETUP_EXCEPT) self.stack_size = ss # restore the current level def SETUP_FINALLY(self): ss = self.stack_size self.stack_size = ss+3 # allow for exceptions self.stack_size = ss+1 # simulate the level after the None is pushed self.setup_block(SETUP_FINALLY) self.stack_size = ss # restore original level def SETUP_LOOP(self): self.setup_block(SETUP_LOOP) def POP_BLOCK(self): if not self.blocks: raise AssertionError("Not currently in a block") why, level, fwd = self.blocks.pop() self.emit(POP_BLOCK) if why!=SETUP_LOOP: if why==SETUP_FINALLY: self.LOAD_CONST(None) fwd() else: self.stack_size = level-3 # stack level resets here else_ = self.JUMP_FORWARD() fwd() return else_ else: return fwd if 'JUMP_IF_TRUE_OR_POP' not in opcode: def JUMP_IF_TRUE_OR_POP(self, address=None): lbl = self.JUMP_IF_TRUE(address) self.POP_TOP() return lbl globals()['JUMP_IF_TRUE_OR_POP'] = -1 if 'JUMP_IF_FALSE_OR_POP' not in opcode: def JUMP_IF_FALSE_OR_POP(self, address=None): lbl = self.JUMP_IF_FALSE(address) self.POP_TOP() return lbl globals()['JUMP_IF_FALSE_OR_POP'] = -1 if 'JUMP_IF_TRUE' not in opcode: def JUMP_IF_TRUE(self, address=None): self.DUP_TOP() return self.POP_JUMP_IF_TRUE(address) else: globals()['POP_JUMP_IF_TRUE'] = -1 if 'JUMP_IF_FALSE' not in opcode: def JUMP_IF_FALSE(self, address=None): self.DUP_TOP() return self.POP_JUMP_IF_FALSE(address) else: globals()['POP_JUMP_IF_FALSE'] = -1 if 'LIST_APPEND' in opcode and LIST_APPEND>=HAVE_ARGUMENT: def LIST_APPEND(self, depth): self.stackchange((depth+1, depth)) self.emit_arg(LIST_APPEND, depth) def assert_loop(self): for why,level,fwd in self.blocks: if why==SETUP_LOOP: return raise AssertionError("Not inside a loop") def BREAK_LOOP(self): self.assert_loop(); self.emit(BREAK_LOOP) self.stack_unknown() def CONTINUE_LOOP(self, label): self.assert_loop() if self.blocks[-1][0]==SETUP_LOOP: op = JUMP_ABSOLUTE # more efficient if not in a nested block else: op = CONTINUE_LOOP return self.jump(op, label) def __call__(self, *args): last = None for ob in args: if hasattr(ob, '__call__'): last = ob(self) else: try: f = generate_types[type(ob)] except KeyError: raise TypeError("Can't generate", ob) else: last = f(self, ob) return last def return_(self, ob=None): return self(ob, Code.RETURN_VALUE) decorate(classmethod) def from_function(cls, function, copy_lineno=False): code = cls.from_code(getattr(function, CODE), copy_lineno) return code decorate(classmethod) def from_code(cls, code, copy_lineno=False): import inspect self = cls.from_spec(code.co_name, *inspect.getargs(code)) if copy_lineno: self.set_lineno(code.co_firstlineno) self.co_filename = code.co_filename self.co_freevars = code.co_freevars # XXX untested! return self decorate(classmethod) def from_spec(cls, name='<lambda>', args=(), var=None, kw=None): self = cls() self.co_name = name self.co_argcount = len(args) self.co_varnames.extend(args) if var: self.co_varnames.append(var) self.co_flags |= CO_VARARGS if kw: self.co_varnames.append(kw) self.co_flags |= CO_VARKEYWORDS def tuple_arg(args): self.UNPACK_SEQUENCE(len(args)) for arg in args: if not isinstance(arg, basestring): tuple_arg(arg) else: self.STORE_FAST(arg) for narg, arg in enumerate(args): if not isinstance(arg, basestring): dummy_name = '.'+str(narg) self.co_varnames[narg] = dummy_name self.LOAD_FAST(dummy_name) tuple_arg(arg) return self def patch_arg(self, offset, oldarg, newarg, op): assert(op!=120) code = self.co_code if (newarg>0xFFFF) and (oldarg<=0xFFFF): raise AssertionError("Can't change argument size", oldarg, newarg) code[offset+1] = newarg & 255 code[offset+2] = (newarg>>8) & 255 if newarg>0xFFFF or oldarg>0xFFFF or op == 120: code[offset+1] = (newarg>>16) & 255 code[offset+2] = (newarg>>24) & 255 code[offset+4] = (newarg>>0) & 255 code[offset+5] = (newarg>>8) & 255 def nested(self, name='<lambda>', args=(), var=None, kw=None, cls=None): if cls is None: cls = self.__class__ code = cls.from_spec(name, args, var, kw) code.co_filename=self.co_filename return code def __iter__(self): i = 0 extended_arg = 0 code = self.co_code n = len(code) while i < n: op = code[i] if op >= HAVE_ARGUMENT: oparg = code[i+1] + code[i+2]*256 + extended_arg extended_arg = 0 if op == EXTENDED_ARG: extended_arg = oparg*long(65536) i+=3 continue yield i, op, oparg i += 3 else: yield i, op, None i += 1 def makefree(self, names): nowfree = dict.fromkeys(self.co_freevars) newfree = [n for n in names if n not in nowfree] if newfree: self.co_freevars += tuple(newfree) self._locals_to_cells() def makecells(self, names): nowcells = dict.fromkeys(self.co_cellvars+self.co_freevars) newcells = [n for n in names if n not in nowcells] if newcells: if not (self.co_flags & CO_OPTIMIZED): raise AssertionError("Can't use cellvars in unoptimized scope") cc = len(self.co_cellvars) nc = len(newcells) self.co_cellvars += tuple(newcells) if self.co_freevars: self._patch( deref_to_deref, dict([(n+cc,n+cc+nc)for n in range(len(self.co_freevars))]) ) self._locals_to_cells() def _locals_to_cells(self): freemap = dict( [(n,p) for p,n in enumerate(self.co_cellvars+self.co_freevars)] ) argmap = dict( [(p,freemap[n]) for p,n in enumerate(self.co_varnames) if n in freemap] ) if argmap: for ofs, op, arg in self: if op==DELETE_FAST and arg in argmap: raise AssertionError( "Can't delete local %r used in nested scope" % self.co_varnames[arg] ) self._patch(fast_to_deref, argmap) def _patch(self, opmap, argmap={}): code = self.co_code for ofs, op, arg in self: if op in opmap: print op if arg in argmap: self.patch_arg(ofs, arg, argmap[arg],op) elif arg is not None: continue code[ofs] = opmap[op] def code(self, parent=None): if self.blocks: raise AssertionError("%d unclosed block(s)" % len(self.blocks)) flags = self.co_flags & ~CO_NOFREE if parent is not None: locals_written = self.locals_written() self.makefree([ n for n in self.co_varnames[ self.co_argcount + ((self.co_flags & CO_VARARGS)==CO_VARARGS) + ((self.co_flags & CO_VARKEYWORDS)==CO_VARKEYWORDS) : ] if n not in locals_written ]) if not self.co_freevars and not self.co_cellvars: flags |= CO_NOFREE elif parent is not None and self.co_freevars: parent.makecells(self.co_freevars) return NEW_CODE( self.co_argcount, len(self.co_varnames), self.co_stacksize, flags, to_code(self.co_code), tuple(self.co_consts), tuple(self.co_names), tuple(self.co_varnames), self.co_filename, self.co_name, self.co_firstlineno, to_code(self.co_lnotab), self.co_freevars, self.co_cellvars )
class Graph: def __init__(self, iterable=()): self.kvl = {} self.has_key = self.kvl.has_key for k, v in iterable: self[k] = v decorate(classmethod) def fromkeys(cls, keys): return cls([(k, k) for k in keys]) def neighbors(self, key): return self.kvl.get(key, []) def __getitem__(self, key): return self.kvl[key][0] def restrict(self, other): if not isinstance(other, Graph): other = Graph(other) kvl = other.kvl return Graph([(k, v) for k, v in self if k in kvl]) def __sub__(self, other): return Graph(Set(self) - Set(other)) def __eq__(self, other): return Set(self) == Set(other) def __ne__(self, other): return Set(self) != Set(other) def __len__(self): return sum([len(v) for v in self.kvl.values()]) def reachable(self, key): oldkey = key stack = [key] found = Set() add = found.add extend = stack.extend while stack: key = stack.pop() if key not in found: next = self.kvl.get(key, []) stack.extend(next) add(key) found.remove(oldkey) return found def __repr__(self): keys = list(self) keys.sort() return "Graph(%r)" % keys def __iter__(self): for k, vl in self.kvl.items(): for v in vl: yield k, v def __setitem__(self, key, val): vl = self.kvl.setdefault(key, []) if val not in vl: vl.append(val) add = __setitem__ def __invert__(self): return Graph([(v, k) for k, v in self]) def __add__(self, other): return Graph(list(self) + list(other)) def __iadd__(self, other): for k, v in other: self[k] = v return self __ior__ = __iadd__ def __or__(self, other): return Graph(list(self) + list(other)) def __mul__(self, other): if not isinstance(other, Graph): other = Graph(other) all = other.kvl return Graph([(k, v2) for k, v in self if v in all for v2 in all[v]]) def __contains__(self, (key, val)): return val in self.kvl.get(key, ())
class Bootstrap(AbstractInterpreter): """Invoke and use an arbitrary 'IExecutable' object This class is designed to allow specification of an arbitrary name or URL on the command line to retrieve and invoke the designated object. If the name is not a scheme-prefixed URL, it is first converted to a name in the 'peak.running.shortcuts' configuration property namespace, thus allowing simpler names to be used. For example, 'runIni' is a shortcut for '"import:peak.running.commands:IniInterpreter"'. If you use a sitewide PEAK_CONFIG file, you can add your own shortcuts to the 'peak.running.shortcuts' namespace. (See the 'peak.ini' file for current shortcuts, and examples of how to define them.) The object designated by the name or URL in 'argv[1]' must be an 'IExecutable'; that is to say it must implement one of the 'IExecutable' sub-interfaces, or else be callable without arguments. (See the 'running.IExecutable' interface for more details.) Here's an example bootstrap script (which is installed as the 'peak' script by the PEAK distribution on 'posix' operating systems):: #!/usr/bin/env python2.2 from peak.running import commands commands.runMain( commands.Bootstrap ) The script above will look up its first supplied command line argument, and then invoke the found object as a command, supplying the remaining command line arguments. """ acceptURLs = True def interpret(self, name): try: factory = lookupCommand(self, name, default=NoSuchSubcommand, acceptURLs=self.acceptURLs) except exceptions.InvalidName: factory = InvalidSubcommandName executable = ICmdLineAppFactory(factory, None) if executable is None: raise InvocationError("Invalid command object", factory, "found at", name) return self.getSubcommand(factory) cmdConfig = binding.Make(list, [ options.Append('-c', '--config', type=str, metavar="INI_FILE", help=".ini-style configuration file(s) to load") ]) decorate(binding.Make) def cmdParent(self): if self.cmdConfig: parent = config.ServiceArea(self) config.loadConfigFiles(parent, self.cmdConfig) return parent def getCommandParent(self): """Get or create a component to be used as the subcommand's parent""" # Default is to use the interpreter as the parent parent = self.cmdParent if parent is None: return self return parent usage = """ Usage: peak [options] NAME_OR_URL arguments... The 'peak' script bootstraps and runs a specified command object or command class. The NAME_OR_URL argument may be a shortcut name defined in the 'peak.running.shortcuts' property namespace, or a URL of a type supported by 'peak.naming'. For example, if you have a class 'MyAppClass' defined in 'MyPackage', you can use: peak import:MyPackage.MyAppClass to invoke it. Arguments to the found object are shifted left one position, so in the example above it will see 'import:MyPackage.MyAppClass' as its 'argv[0]'. The named object must implement one of the 'peak.running' command interfaces, or be callable. See the 'Bootstrap' class in 'peak.running.commands' for more details on creating command objects for use with 'peak'. For the list of available shortcut names, see '%s'""" % config.packageFile( 'peak', 'peak.ini').address if os.environ.get('PEAK_CONFIG'): usage += " and '%s'" % os.environ['PEAK_CONFIG'] usage += ".\n" def showHelp(self): """Display usage message on stderr""" super(Bootstrap, self).showHelp() from peak.util.columns import lsFormat print >> self.stderr, "Available commands:" print >> self.stderr self.stderr.writelines( lsFormat(80, config.Namespace('peak.running.shortcuts', self).keys())) print >> self.stderr return 0