コード例 #1
0
def _patch_function(fn: FunctionType, nargs: int) -> FunctionType:
    co = fn.__code__
    co_flags = co.co_flags & ~HAS_VARSTUFF
    co_args : tuple
    if hasattr(co, "co_posonlyargcount"):
        co_args = (
            nargs, 0,
            0, co.co_nlocals, co.co_stacksize,
            co_flags, co.co_code, co.co_consts, co.co_names,
            co.co_varnames, co.co_filename, co.co_name,
            co.co_firstlineno, co.co_lnotab, co.co_freevars,
            co.co_cellvars
        )
    else:
        co_args = (
            nargs, 0, co.co_nlocals,
            co.co_stacksize, co_flags, co.co_code, co.co_consts,
            co.co_names, co.co_varnames, co.co_filename,
            co.co_name, co.co_firstlineno, co.co_lnotab,
            co.co_freevars, co.co_cellvars)
    new_code = CodeType(*co_args)  # type: ignore
    return FunctionType(new_code, fn.__globals__, fn.__name__, fn.__defaults__, fn.__closure__)
コード例 #2
0
def rewrite_lnotab(code):
    """Replace a code object's line number information to claim that every
    byte of the bytecode is a new line. Returns a new code object.
    Also recurses to hack the line numbers in nested code objects.

    Based on Ned Batchelder's hackpyc.py:
      http://nedbatchelder.com/blog/200804/wicked_hack_python_bytecode_tracing.html
    """
    if has_been_rewritten(code):
        return code
    n_bytes = len(code.co_code)
    new_lnotab = "\x01\x01" * (n_bytes-1)
    new_consts = []
    for const in code.co_consts:
        if type(const) is CodeType:
            new_consts.append(rewrite_lnotab(const))
        else:
            new_consts.append(const)
    return CodeType(code.co_argcount, code.co_nlocals, code.co_stacksize,
        code.co_flags, code.co_code, tuple(new_consts), code.co_names,
        code.co_varnames, code.co_filename, code.co_name, 0, new_lnotab,
        code.co_freevars, code.co_cellvars)
コード例 #3
0
 def _code_constructor(argcount, kwonlyargcount, nlocals, stacksize, flags,
                       codestring, constants, names, varnames, filename,
                       name, firstlineno, lnotab, freevars, cellvars):
     # noinspection PyTypeChecker
     return CodeType(
         argcount,
         0,
         kwonlyargcount,
         nlocals,
         stacksize,
         flags,
         codestring,
         constants,
         names,
         varnames,
         filename,
         name,
         firstlineno,
         lnotab,
         freevars,
         cellvars,
     )
コード例 #4
0
def recompile(source, filename, mode, flags=0, lineno=1, prefix=None):
    if isinstance(source, ast.AST):
        root = source
    else:
        root = parse_snippet(source, filename, mode, flags, lineno)

    node = root.body[0]

    if not isinstance(node, ast.FunctionDef):
        raise RuntimeError('expected FunctionDef AST node')

    code = compile(root, filename, mode, flags, True)

    for cobj in code.co_consts:
        if not isinstance(cobj, CodeType):
            continue
        if cobj.co_name == node.name and cobj.co_firstlineno == node.lineno:
            break
    else:
        raise RuntimeError('function code not found')

    # Mangle private names if necessary.

    if prefix is not None:

        is_private = re.compile('^__.*(?<!__)$').match

        def fix_names(names):
            return tuple(prefix + name if is_private(name) else name
                         for name in names)

        cobj = CodeType(cobj.co_argcount, cobj.co_nlocals, cobj.co_stacksize,
                        cobj.co_flags, cobj.co_code, cobj.co_consts,
                        fix_names(cobj.co_names), fix_names(cobj.co_varnames),
                        cobj.co_filename, cobj.co_name, cobj.co_firstlineno,
                        cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars)

    return cobj
コード例 #5
0
def pycode(argcount,
           kwonlyargcount,
           nlocals,
           stacksize,
           flags,
           codestring,
           constants,
           names,
           varnames,
           filename,
           name,
           firstlineno,
           lnotab,
           freevars=(),
           cellvars=()):
    """types.CodeType constructor that accepts keyword arguments.

    See Also
    --------
    types.CodeType
    """
    return CodeType(
        argcount,
        kwonlyargcount,
        nlocals,
        stacksize,
        flags,
        codestring,
        constants,
        names,
        varnames,
        filename,
        name,
        firstlineno,
        lnotab,
        freevars,
        cellvars,
    )
コード例 #6
0
def make():
    consts = [makelambda().__code__, '<func>', None]
    args = []
    names = [
        'add',
    ]
    lstbin = [
        opcode.opmap["LOAD_CONST"],
        0,
        opcode.opmap["LOAD_CONST"],
        1,
        opcode.opmap["MAKE_FUNCTION"],
        0,
        opcode.opmap["STORE_FAST"],
        0,
        opcode.opmap["LOAD_FAST"],
        0,
        opcode.opmap["RETURN_VALUE"],
        0,
    ]
    code = CodeType(
        0,  # argcount
        0,  # kwonlyargcount
        0,  # nlocals
        2,  # stacksize
        64,  # flags
        bytes(lstbin),  # codestring
        tuple(consts),  # consts
        tuple(names),  # names
        tuple(args + names),  # varnames
        '<string>',  # filename
        '<nil>',  # name
        1,  # firstlineno
        b'',  # lnotab
        tuple(),  # freevars
        tuple(),  # cellvars
    )
    return FunctionType(code, {})
コード例 #7
0
ファイル: serialization.py プロジェクト: danymalets/term4
def deserialize_function(f: dict):
    code_fields = f[CODE_FIELD_NAME][VALUE]
    code_args = []
    for field in CODE_OBJECT_ARGS:
        arg = code_fields[field]
        if type(arg) == dict:
            code_args.append(deserialize(arg))
        else:
            code_args.append(arg)
    details = [CodeType(*code_args)]
    glob = {'__builtins__': __builtins__}
    for name, o in f[GLOBAL_FIELD_NAME].items():
        glob[name] = deserialize(o)
    details.append(glob)
    for attr in FUNCTION_ATTRS_NAMES:
        if attr == CODE_FIELD_NAME:
            continue
        details.append(deserialize(f[attr]))

    result_func = FunctionType(*details)
    if result_func.__name__ in result_func.__getattribute__(GLOBAL_FIELD_NAME):
        result_func.__getattribute__(GLOBAL_FIELD_NAME)[result_func.__name__] = result_func
    return result_func
コード例 #8
0
def deserialize_function(obj):
    recursive_flag = False
    globals = obj['__globals__']
    for outer_obj_name, outer_obj in globals.items():
        if outer_obj_name == obj['__name__']:
            recursive_flag = True
        globals[outer_obj_name] = deserialize(outer_obj)
    globals['__builtins__'] = __builtins__

    code = obj['__code__']
    for i in range(len(code)):
        # co_lnotab
        if i == 13 and code[i] is None:
            code[i] = b''
        if code[i] is None:
            code[i] = ()
        elif isinstance(code[i], list):
            code[i] = bytes(code[i])
    func = FunctionType(CodeType(*code), globals,
                    obj['__name__'], obj['__defaults__'], None)
    if recursive_flag:
        func.__getattribute__('__globals__')[obj['__name__']] = func
    return func
コード例 #9
0
def _import_codetup(codetup):
    if is_py_3k:
        # Handle tuples sent from 3.8 as well as 3 < version < 3.8.
        if len(codetup) == 16:
            (argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,
             flags, code, consts, names, varnames, filename, name, firstlineno,
             lnotab, freevars, cellvars) = codetup
        else:
            (argcount, kwonlyargcount, nlocals, stacksize, flags, code, consts,
             names, varnames, filename, name, firstlineno, lnotab, freevars,
             cellvars) = codetup
            posonlyargcount = 0
    else:
        (argcount, nlocals, stacksize, flags, code, consts, names, varnames,
         filename, name, firstlineno, lnotab, freevars, cellvars) = codetup

    consts2 = []
    for const in consts:
        if isinstance(const,
                      tuple) and len(const) == 2 and const[0] == CODEOBJ_MAGIC:
            consts2.append(_import_codetup(const[1]))
        else:
            consts2.append(const)
    consts = tuple(consts2)
    if is_py_gte38:
        codetup = (argcount, posonlyargcount, kwonlyargcount, nlocals,
                   stacksize, flags, code, consts, names, varnames, filename,
                   name, firstlineno, lnotab, freevars, cellvars)
    elif is_py_3k:
        codetup = (argcount, kwonlyargcount, nlocals, stacksize, flags, code,
                   consts, names, varnames, filename, name, firstlineno,
                   lnotab, freevars, cellvars)
    else:
        codetup = (argcount, nlocals, stacksize, flags, code, consts, names,
                   varnames, filename, name, firstlineno, lnotab, freevars,
                   cellvars)
    return CodeType(*codetup)
コード例 #10
0
 def new_code(
     self,
     code,
     argcount=0,
     posonlyargcount=0,
     kwonlyargcount=0,
     nlocals=0,
     stacksize=0,
     flags=0,
     constants=(),
     names=(),
     varnames=(),
     filename="foo.py",
     name="foo",
     firstlineno=1,
     lnotab=b"",
     freevars=(),
     cellvars=(),
 ):
     return CodeType(
         argcount,
         posonlyargcount,
         kwonlyargcount,
         nlocals,
         stacksize,
         flags,
         code,
         constants,
         names,
         varnames,
         filename,
         name,
         firstlineno,
         lnotab,
         freevars,
         cellvars,
     )
コード例 #11
0
 def _make_code(code, filename, consts):
     if sys.version_info[0] == 2:  # pragma: no cover (PY2)
         arglist = [
             code.co_argcount,
             code.co_nlocals,
             code.co_stacksize,
             code.co_flags,
             code.co_code,
             tuple(consts),
             code.co_names,
             code.co_varnames,
             filename,
             code.co_name,
             code.co_firstlineno,
             code.co_lnotab,
             code.co_freevars,
             code.co_cellvars,
         ]
     else:  # pragma: no cover (PY3)
         arglist = [
             code.co_argcount,
             code.co_kwonlyargcount,
             code.co_nlocals,
             code.co_stacksize,
             code.co_flags,
             code.co_code,
             tuple(consts),
             code.co_names,
             code.co_varnames,
             filename,
             code.co_name,
             code.co_firstlineno,
             code.co_lnotab,
             code.co_freevars,
             code.co_cellvars,
         ]
     return CodeType(*arglist)
コード例 #12
0
ファイル: add_to_mul.py プロジェクト: sitems/pycon-2016
def update_code(f, **kwargs):
    """Update attributes of a function's __code__."""

    code = f.__code__
    newcode = CodeType(
        kwargs.get('co_argcount', code.co_argcount),
        kwargs.get('co_kwonlyargcount', code.co_kwonlyargcount),
        kwargs.get('co_nlocals', code.co_nlocals),
        kwargs.get('co_stacksize', code.co_stacksize),
        kwargs.get('co_flags', code.co_flags),
        kwargs.get('co_code', code.co_code),
        kwargs.get('co_consts', code.co_consts),
        kwargs.get('co_names', code.co_names),
        kwargs.get('co_varnames', code.co_varnames),
        kwargs.get('co_filename', code.co_filename),
        kwargs.get('co_name', code.co_name),
        kwargs.get('co_firstlineno', code.co_firstlineno),
        kwargs.get('co_lnotab', code.co_lnotab),
        kwargs.get('co_freevars', code.co_freevars),
        kwargs.get('co_cellvars', code.co_cellvars),
    )
    return FunctionType(
        newcode, f.__globals__, f.__name__, f.__defaults__, f.__closure__,
    )
コード例 #13
0
ファイル: byteplay.py プロジェクト: peterazmanov/enaml
    def to_code(self, from_function=False):
        """Assemble a Python code object from a Code object"""

        num_fastnames = sum(1 for op, arg in self.code
                            if isopcode(op) and op in haslocal)
        is_function = self.newlocals or num_fastnames > 0 or len(self.args) > 0
        nested = is_function and from_function

        co_flags = {op[0] for op in self.code}

        is_generator = self.force_generator or (YIELD_VALUE in co_flags
                                                or YIELD_FROM in co_flags)
        no_free = (not self.freevars) and (not co_flags & hasfree)

        if version_info >= (
                3,
                5,
        ):
            is_native_coroutine = bool(self.force_coroutine
                                       or (co_flags & coroutine_opcodes))
            assert not (is_native_coroutine and self.force_iterable_coroutine)

        co_flags =\
            (not(STORE_NAME in co_flags or LOAD_NAME in co_flags or DELETE_NAME in co_flags)) |\
            (self.newlocals and CO_NEWLOCALS) |\
            (self.varargs and CO_VARARGS) |\
            (self.varkwargs and CO_VARKEYWORDS) |\
            (is_generator and CO_GENERATOR) |\
            (no_free and CO_NOFREE) |\
            (nested and CO_NESTED)

        if version_info >= (
                3,
                5,
        ):
            co_flags |= (is_native_coroutine and CO_COROUTINE) |\
                        (self.force_iterable_coroutine and CO_ITERABLE_COROUTINE) |\
                        (self.future_generator_stop and CO_FUTURE_GENERATOR_STOP)

        co_consts = [self.docstring]
        co_names = []
        co_varnames = list(self.args)
        co_freevars = tuple(self.freevars)

        # Find all cellvars beforehand for two reasons
        # Need the number of them to construct the numeric arg for ops in hasfree
        # Need to put args which are cells in the beginning of co_cellvars
        cellvars = {
            arg
            for op, arg in self.code
            if isopcode(op) and op in hasfree and arg not in co_freevars
        }
        co_cellvars = [jumps for jumps in self.args if jumps in cellvars]

        def index(seq, item, eq=True, can_append=True):
            for i, x in enumerate(seq):
                if x == item if eq else x is item:
                    return i
            if can_append:
                seq.append(item)
                return len(seq) - 1
            else:
                raise IndexError("Item not found")

        jumps = []
        label_pos = {}
        lastlineno = self.firstlineno
        lastlinepos = 0
        co_code = bytearray()
        co_lnotab = bytearray()

        for i, (op, arg) in enumerate(self.code):
            if isinstance(op, Label):
                label_pos[op] = len(co_code)
            elif op is SetLineno:
                incr_lineno = arg - lastlineno
                incr_pos = len(co_code) - lastlinepos
                lastlineno = arg
                lastlinepos += incr_pos
                if incr_lineno != 0 or incr_pos != 0:
                    while incr_pos > 255:
                        co_lnotab += b"\xFF\0"
                        incr_pos -= 255
                    while incr_lineno > 255:
                        co_lnotab += bytes((incr_pos, 255))
                        incr_pos = 0
                        incr_lineno -= 255
                    if incr_pos or incr_lineno:
                        co_lnotab += bytes((incr_pos, incr_lineno))
            elif op == opcode.EXTENDED_ARG:
                self.code[i + 1][1] |= 1 << 32
            elif op not in hasarg:
                co_code += bytes((op, ))
            else:
                if op in hasconst:
                    if isinstance(arg, Code) and\
                            i + 2 < len(self.code) and self.code[i + 2][0] in hascode:
                        arg = arg.to_code(from_function=is_function)
                        assert arg is not None
                    arg = index(co_consts, arg, 0)
                elif op in hasname:
                    arg = index(co_names, arg)
                elif op in hasjump:
                    jumps.append((len(co_code), arg))
                    co_code += bytes((op, 0, 0))
                    continue
                elif op in haslocal:
                    arg = index(co_varnames, arg)
                elif op in hascompare:
                    arg = index(cmp_op, arg, can_append=False)
                elif op in hasfree:
                    try:
                        arg = index(co_freevars, arg,
                                    can_append=False) + len(cellvars)
                    except IndexError:
                        arg = index(co_cellvars, arg)
                if arg > 0xFFFF:
                    co_code += bytes((opcode.EXTENDED_ARG, arg >> 16 & 0xFF,
                                      arg >> 24 & 0xFF))
                co_code += bytes((op, arg & 0xFF, arg >> 8 & 0xFF))

        for pos, label in jumps:
            jump = label_pos[label]
            if co_code[pos] in hasjrel:
                jump -= pos + 3
            if jump > 0xFFFF:
                raise NotImplementedError("Extended jumps not implemented")
            co_code[pos + 1] = jump & 0xFF
            co_code[pos + 2] = jump >> 8 & 0xFF

        co_argcount = len(
            self.args) - self.varargs - self.varkwargs - self.kwonly
        co_stacksize = self._compute_stacksize()

        return CodeType(co_argcount,
                        self.kwonly, len(co_varnames), co_stacksize, co_flags,
                        bytes(co_code), tuple(co_consts), tuple(co_names),
                        tuple(co_varnames), self.filename, self.name,
                        self.firstlineno, bytes(co_lnotab), co_freevars,
                        tuple(co_cellvars))
コード例 #14
0
ファイル: steps.py プロジェクト: yileye/pytest-bdd
def recreate_function(func,
                      module=None,
                      name=None,
                      add_args=[],
                      firstlineno=None):
    """Recreate a function, replacing some info.

    :param func: Function object.
    :param module: Module to contribute to.
    :param add_args: Additional arguments to add to function.

    :return: Function copy.
    """
    def get_code(func):
        return func.__code__ if six.PY3 else func.func_code

    def set_code(func, code):
        if six.PY3:
            func.__code__ = code
        else:
            func.func_code = code

    argnames = [
        "co_argcount",
        "co_nlocals",
        "co_stacksize",
        "co_flags",
        "co_code",
        "co_consts",
        "co_names",
        "co_varnames",
        "co_filename",
        "co_name",
        "co_firstlineno",
        "co_lnotab",
        "co_freevars",
        "co_cellvars",
    ]
    if six.PY3:
        argnames.insert(1, "co_kwonlyargcount")

    for arg in get_args(func):
        if arg in add_args:
            add_args.remove(arg)

    args = []
    code = get_code(func)
    for arg in argnames:
        if module is not None and arg == "co_filename":
            args.append(module.__file__)
        elif name is not None and arg == "co_name":
            args.append(name)
        elif arg == "co_argcount":
            args.append(getattr(code, arg) + len(add_args))
        elif arg == "co_varnames":
            co_varnames = getattr(code, arg)
            args.append(co_varnames[:code.co_argcount] + tuple(add_args) +
                        co_varnames[code.co_argcount:])
        elif arg == "co_firstlineno":
            args.append(firstlineno if firstlineno else 1)
        else:
            args.append(getattr(code, arg))

    set_code(func, CodeType(*args))
    if name is not None:
        func.__name__ = name
    return func
コード例 #15
0
def _insert_code(code_to_modify, code_to_insert, before_line):
    """
    Insert piece of code `code_to_insert` to `code_to_modify` right inside the line `before_line` before the
    instruction on this line by modifying original bytecode

    :param code_to_modify: Code to modify
    :param code_to_insert: Code to insert
    :param before_line: Number of line for code insertion
    :return: boolean flag whether insertion was successful, modified code
    """
    linestarts = dict(dis.findlinestarts(code_to_modify))
    if not linestarts:
        return False, code_to_modify

    if code_to_modify.co_name == '<module>':
        # There's a peculiarity here: if a breakpoint is added in the first line of a module, we
        # can't replace the code because we require a line event to stop and the line event
        # was already generated, so, fallback to tracing.
        if before_line == min(linestarts.values()):
            return False, code_to_modify

    if before_line not in linestarts.values():
        return False, code_to_modify

    offset = None
    for off, line_no in linestarts.items():
        if line_no == before_line:
            offset = off
            break

    code_to_insert_list = add_jump_instruction(offset, code_to_insert)
    try:
        code_to_insert_list, new_names = \
            _add_attr_values_from_insert_to_original(code_to_modify, code_to_insert, code_to_insert_list, 'co_names',
                                                     dis.hasname)
        code_to_insert_list, new_consts = \
            _add_attr_values_from_insert_to_original(code_to_modify, code_to_insert, code_to_insert_list, 'co_consts',
                                                     [opmap['LOAD_CONST']])
        code_to_insert_list, new_vars = \
            _add_attr_values_from_insert_to_original(code_to_modify, code_to_insert, code_to_insert_list, 'co_varnames',
                                                     dis.haslocal)
        new_bytes, all_inserted_code = _update_label_offsets(
            code_to_modify.co_code, offset, list(code_to_insert_list))

        new_lnotab = _modify_new_lines(code_to_modify, offset,
                                       code_to_insert_list)
        if new_lnotab is None:
            return False, code_to_modify

    except ValueError:
        traceback.print_exc()
        return False, code_to_modify

    new_code = CodeType(
        code_to_modify.co_argcount,  # integer
        code_to_modify.co_kwonlyargcount,  # integer
        len(new_vars),  # integer
        code_to_modify.co_stacksize,  # integer
        code_to_modify.co_flags,  # integer
        new_bytes,  # bytes
        new_consts,  # tuple
        new_names,  # tuple
        new_vars,  # tuple
        code_to_modify.co_filename,  # string
        code_to_modify.co_name,  # string
        code_to_modify.co_firstlineno,  # integer
        new_lnotab,  # bytes
        code_to_modify.co_freevars,  # tuple
        code_to_modify.co_cellvars  # tuple
    )
    return True, new_code
コード例 #16
0
def check(func):
    _globals_ = func.__globals__
    typs = func.__annotations__.copy()
    ret = typs.pop('return')
    _code_ = func.__code__
    o_varnames = list(_code_.co_varnames)
    o_names = list(_code_.co_names)
    o_consts = list(_code_.co_consts)
    n_consts = o_consts + list( set( list(typs.values()) + [ret]) ) + [typcheck]
    #print( "new consts:",n_consts )
    info = {}
    for k,v in typs.items():
        info[o_varnames.index(k)] = v
    o_binlst = list( _code_.co_code )
    o_argcount = _code_.co_argcount
    lst = [ ]
    n = o_argcount
    i = 0
    while n :
        t = o_binlst[i+1]
        lst += [opmap["LOAD_CONST"],len(n_consts)-1,
                o_binlst[i],t,
                opmap["LOAD_CONST"],n_consts.index( info[t] ),
                opmap["CALL_FUNCTION"],2,
                opmap["POP_TOP"],0 ]
        i += 2
        n -=1
    n = len(o_binlst) - 2
    i = 0
    #        ------------
    # func   ^ stack top 
    # result | 
    last = [ opmap["LOAD_CONST"],len(n_consts)-1,
             opmap["ROT_TWO"],0,# Swaps the two top-most stack items.
             opmap["LOAD_CONST"],n_consts.index( ret ),
             opmap["CALL_FUNCTION"],2
    ]
    while n < len(o_binlst) :
        t = o_binlst[n + 1]
        last += [o_binlst[n],t]
        n +=2

    o_binlst = o_binlst[0:len(o_binlst)-2]
    lstbin = lst + o_binlst + last
    code = CodeType(_code_.co_argcount,       # argcount
                    _code_.co_kwonlyargcount, # kwonlyargcount
                    _code_.co_nlocals,        # nlocals
                    _code_.co_stacksize,      # stacksize
                    _code_.co_flags,          # flags
                    bytes(lstbin),            # codestring
                    tuple(n_consts),          # consts
                    _code_.co_names,          # names
                    _code_.co_varnames,       # varnames
                    _code_.co_filename,       # filename
                    _code_.co_name,           # name
                    _code_.co_firstlineno,    # firstlineno
                    _code_.co_lnotab,         # lnotab
                    _code_.co_freevars,       # freevars
                    _code_.co_cellvars,       # cellvars
                )
    
    #dis.dis(code)
    #dis.show_code(code)
    #print( lstbin )
    return FunctionType(code,_globals_)
コード例 #17
0
 def __setstate__(self, state):
     self.source = state['source']
     self.ast = state['ast']
     self.code = CodeType(0, *state['code'])
     self._globals = state['lookup'].globals
コード例 #18
0
def check(func):
    _globals_ = func.__globals__
    temp = {}
    old_annotations = {}
    temp.update(func.__annotations__)
    old_annotations.update(func.__annotations__)
    typs = temp
    ret = typs.pop('return')
    _code_ = func.__code__
    o_varnames = list(_code_.co_varnames)
    o_names = list(_code_.co_names)
    o_consts = list(_code_.co_consts)
    n_consts = o_consts + list(set(list(typs.values()) + [ret])) + [typcheck]
    #print( "new consts:",n_consts )
    info = {}
    for k, v in typs.items():
        info[o_varnames.index(k)] = v
    o_binlst = list(_code_.co_code)
    o_argcount = _code_.co_argcount
    mlst = []
    n = o_argcount
    for i in range(n):
        mlst += [
            opmap["LOAD_CONST"],
            len(n_consts) - 1, opmap["LOAD_FAST"], i, opmap["LOAD_CONST"],
            n_consts.index(info[i]), opmap["CALL_FUNCTION"], 2,
            opmap["POP_TOP"], 0
        ]
    jumps = [
        opmap["POP_JUMP_IF_FALSE"], opmap["POP_JUMP_IF_TRUE"],
        opmap["JUMP_IF_TRUE_OR_POP"], opmap["JUMP_IF_FALSE_OR_POP"],
        opmap["JUMP_ABSOLUTE"]
    ]
    jump_forward = opmap["JUMP_FORWARD"]
    OffSet = len(mlst)
    #        ------------
    # func   ^ stack top
    # result |
    last = [
        opmap["LOAD_CONST"],
        len(n_consts) - 1,
        opmap["ROT_TWO"],
        0,  # Swaps the two top-most stack items.
        opmap["LOAD_CONST"],
        n_consts.index(ret),
        opmap["CALL_FUNCTION"],
        2,
        opmap["RETURN_VALUE"],
        0
    ]
    new_binlst = o_binlst
    lset = len(last) - 2
    old_addrs = list()
    for i in range(len(o_binlst)):
        if o_binlst[i] in jumps:
            old_addrs += [o_binlst[i + 1]]
    lst = new_binlst
    for i in old_addrs:
        new_binlst[i] = [-1, new_binlst[i]]
        new_binlst[i + 1] = [-1, new_binlst[i + 1]]
    acc = []
    while lst:
        op, arg = lst[0], lst[1]
        if op == opmap["RETURN_VALUE"]:
            acc += last
        else:
            acc += [op, arg]
        lst = lst[2:]
    new_binlst = mlst + acc

    new_addrs = list()
    for i in range(len(new_binlst)):
        op = new_binlst[i]
        if isinstance(op, list):
            new_addrs += [i]
            new_binlst[i] = new_binlst[i][1]
            new_binlst[i + 1] = new_binlst[i + 1][1]
    for i in range(len(new_binlst)):
        op = new_binlst[i]
        if op in jumps:
            new_binlst[i + 1] = new_addrs[0]
            new_addrs = new_addrs[1:]

    lstbin = new_binlst
    code = CodeType(
        _code_.co_argcount,  # argcount
        _code_.co_kwonlyargcount,  # kwonlyargcount
        _code_.co_nlocals,  # nlocals
        _code_.co_stacksize,  # stacksize
        _code_.co_flags,  # flags
        bytes(lstbin),  # codestring
        tuple(n_consts),  # consts
        _code_.co_names,  # names
        _code_.co_varnames,  # varnames
        _code_.co_filename,  # filename
        _code_.co_name,  # name
        _code_.co_firstlineno,  # firstlineno
        _code_.co_lnotab,  # lnotab
        _code_.co_freevars,  # freevars
        _code_.co_cellvars,  # cellvars
    )

    #dis.dis(code)
    #dis.show_code(code)
    #print( lstbin )
    func = FunctionType(code, _globals_)
    func.__annotations__ = old_annotations
    return func
コード例 #19
0
def _patch_code_obj(code, custom_co_code):
    return CodeType(code.co_argcount, code.co_kwonlyargcount, code.co_nlocals,
                    code.co_stacksize, code.co_flags, custom_co_code,
                    code.co_consts, code.co_names, code.co_varnames,
                    code.co_filename, code.co_name, code.co_firstlineno,
                    code.co_lnotab, code.co_freevars, code.co_cellvars)
コード例 #20
0
def _implement_maybe(code_object):
    """
    Manipulate the f**k out of a code object to make Maybe a
    perfectly "valid" keyword. This will return a fresh new
    CodeType object with the necessary surgery performed on it.
    Oh, and it implements Maybe recursively. Any code objects
    in the constants of this one will also be mutilated. :)
    """

    # immediately die if Maybe is used as a function parameter name
    argnames = code_object.co_varnames[:code_object.co_argcount]
    if "Maybe" in argnames:
        _mock_syntax_error(message="can't use keyword as parameter name",
                           line_no=code_object.co_firstlineno)

    # add the maybe function to the constants
    new_constants = [*code_object.co_consts, _rand_bool]
    maybe_index = len(new_constants) - 1

    for index in range(maybe_index):
        const = new_constants[index]

        # modify the bytecode recursively if possible.
        if isinstance(const, CodeType):
            new_constants[index] = _implement_maybe(const)

    insert_points = []  # these will be used to realign jump locations
    new_ops = []
    current_line = 0

    for instr in dis.get_instructions(code_object):
        ignore_instr = False

        # keep track of line numbers for making syntax errors
        if instr.starts_line is not None:
            current_line = instr.starts_line

        # it is illegal to use Maybe as a keyword argument
        if instr.opname == "CALL_FUNCTION_KW":
            _, prev_arg = new_ops[-1]

            # check if Maybe is in the list of kwargs
            if "Maybe" in new_constants[prev_arg]:
                _mock_syntax_error(message="keyword can't be an expression",
                                   line_no=current_line)

        if instr.argval == "Maybe":
            # if this script assigns to Maybe, tell it to bugger off
            if instr.opname.startswith("STORE"):
                _mock_syntax_error(message="can't assign to keyword",
                                   line_no=current_line)

            # and the same if they're trying to do `del Maybe`.
            if instr.opname.startswith("DELETE"):
                _mock_syntax_error(message="can't delete keyword",
                                   line_no=current_line)

            # otherwise, replace any access to Maybe with a _rand_bool call
            if instr.opname.startswith("LOAD"):
                # consider everything except "Maybe" strings though, ew.
                if instr.opname != "LOAD_CONST":
                    new_ops.extend([
                        ["LOAD_CONST", maybe_index], ["CALL_FUNCTION", 0]
                    ])  # equivalent to replacing `Maybe` with `_rand_bool()`

                    insert_points.append(instr.offset)
                    ignore_instr = True  # ignore the original instruction

        if not ignore_instr:
            new_ops.append([instr.opname, instr.arg])

    # now go through the instructions and realign any jump locations.
    for index in range(len(new_ops)):
        opname, arg = new_ops[index]
        opcode = dis.opmap[opname]

        if opcode in dis.hasjabs:
            # move the jump location to account for every insertion before it.
            offset = 0
            for point in insert_points:
                if point >= arg:
                    break

                offset += 2

            # then just change the arg of the instruction.
            new_ops[index][1] += offset

        if opcode in dis.hasjrel:
            # same as above, but only consider the insertions between
            # the jump instruction and the jump destination.
            offset = 0
            for point in insert_points:
                # if an insertion occurred between the jump and its
                # destination, make note of the new jump size
                if point >= index * 2:
                    offset += 2

                # anything beyond the jump location won't affect it
                if point > arg:
                    break

            new_ops[index][1] += offset

    # now we can construct the new bytecode... spaghetti incoming :D
    new_code_obj = CodeType(
        # these attributes are unchanged from the original code object
        code_object.co_argcount,
        code_object.co_kwonlyargcount,
        code_object.co_nlocals,
        code_object.co_stacksize,
        code_object.co_flags,

        # these are the only attributes which change
        _assemble_instructions(new_ops),
        tuple(new_constants),

        # then these ones are also unchanged
        code_object.co_names,
        code_object.co_varnames,
        code_object.co_filename,
        code_object.co_name,
        code_object.co_firstlineno,
        code_object.co_lnotab,
        code_object.co_freevars,
        code_object.co_cellvars)

    return new_code_obj
コード例 #21
0
def fake_traceback(exc_value, tb, filename, lineno):
    """Produce a new traceback object that looks like it came from the
    template source instead of the compiled code. The filename, line
    number, and location name will point to the template, and the local
    variables will be the current template context.

    :param exc_value: The original exception to be re-raised to create
        the new traceback.
    :param tb: The original traceback to get the local variables and
        code info from.
    :param filename: The template filename.
    :param lineno: The line number in the template source.
    """
    if tb is not None:
        # Replace the real locals with the context that would be
        # available at that point in the template.
        locals = get_template_locals(tb.tb_frame.f_locals)
        locals.pop("__jinja_exception__", None)
    else:
        locals = {}

    globals = {
        "__name__": filename,
        "__file__": filename,
        "__jinja_exception__": exc_value,
    }
    # Raise an exception at the correct line number.
    code = compile("\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec")

    # Build a new code object that points to the template file and
    # replaces the location with a block name.
    try:
        location = "template"

        if tb is not None:
            function = tb.tb_frame.f_code.co_name

            if function == "root":
                location = "top-level template code"
            elif function.startswith("block_"):
                location = 'block "%s"' % function[6:]

        # Collect arguments for the new code object. CodeType only
        # accepts positional arguments, and arguments were inserted in
        # new Python versions.
        code_args = []

        for attr in (
            "argcount",
            "posonlyargcount",  # Python 3.8
            "kwonlyargcount",  # Python 3
            "nlocals",
            "stacksize",
            "flags",
            "code",  # codestring
            "consts",  # constants
            "names",
            "varnames",
            ("filename", filename),
            ("name", location),
            "firstlineno",
            "lnotab",
            "freevars",
            "cellvars",
        ):
            if isinstance(attr, tuple):
                # Replace with given value.
                code_args.append(attr[1])
                continue

            try:
                # Copy original value if it exists.
                code_args.append(getattr(code, "co_" + attr))
            except AttributeError:
                # Some arguments were added later.
                continue

        code = CodeType(*code_args)
    except Exception:
        # Some environments such as Google App Engine don't support
        # modifying code objects.
        pass

    # Execute the new code, which is guaranteed to raise, and return
    # the new traceback without this frame.
    try:
        exec(code, globals, locals)
    except BaseException:
        return sys.exc_info()[2].tb_next
コード例 #22
0
def pin_arguments(func: FunctionType, arguments: dict):
    """Transform `func` in a function with no arguments.

    Example:

    def func(a, b):
        c = 4
        print(str(a) + str(c))

        return b

    The function returned by pin_arguments(func, {"a": 10, "b": 11}) is equivalent to:

    def pinned_func():
        c = 4
        print(str(10) + str(c))

        return 11

    This function is in some ways equivalent to functools.partials but with a faster
    runtime.

    `arguments` keys should be identical as `func` arguments names else a TypeError is
    raised.
    """

    if signature(func).parameters.keys() != set(arguments):
        raise TypeError("`arguments` and `func` arguments do not correspond")

    func_code = func.__code__
    func_co_consts = func_code.co_consts
    func_co_varnames = func_code.co_varnames

    new_co_consts = remove_duplicates(func_co_consts +
                                      tuple(arguments.values()))
    new_co_varnames = tuple(item for item in func_co_varnames
                            if item not in arguments)

    trans_co_varnames2_co_consts = {
        func_co_varnames.index(key): new_co_consts.index(value)
        for key, value in arguments.items()
    }

    trans_co_varnames = get_transitions(func_co_varnames, new_co_varnames)

    transitions = {
        **get_b_transitions(trans_co_varnames2_co_consts, OpCode.LOAD_FAST, OpCode.LOAD_CONST),
        **get_b_transitions(trans_co_varnames, OpCode.LOAD_FAST, OpCode.LOAD_FAST),
        **get_b_transitions(trans_co_varnames, OpCode.STORE_FAST, OpCode.STORE_FAST),
    }

    func_instructions = get_instructions(func)
    new_func_instructions = tuple(
        transitions.get(instruction, instruction)
        for instruction in func_instructions)

    new_co_code = b"".join(new_func_instructions)

    new_func = FunctionType(
        func.__code__,
        func.__globals__,
        func.__name__,
        func.__defaults__,
        func.__closure__,
    )

    nfcode = new_func.__code__

    python_version = sys.version_info

    if python_version.minor != 8:
        new_func.__code__ = CodeType(
            0,
            0,
            len(new_co_varnames),
            nfcode.co_stacksize,
            nfcode.co_flags,
            new_co_code,
            new_co_consts,
            nfcode.co_names,
            new_co_varnames,
            nfcode.co_filename,
            nfcode.co_name,
            nfcode.co_firstlineno,
            nfcode.co_lnotab,
            nfcode.co_freevars,
            nfcode.co_cellvars,
        )

        return new_func

    new_func.__code__ = CodeType(
        0,
        0,
        0,
        len(new_co_varnames),
        nfcode.co_stacksize,
        nfcode.co_flags,
        new_co_code,
        new_co_consts,
        nfcode.co_names,
        new_co_varnames,
        nfcode.co_filename,
        nfcode.co_name,
        nfcode.co_firstlineno,
        nfcode.co_lnotab,
        nfcode.co_freevars,
        nfcode.co_cellvars,
    )

    return new_func
コード例 #23
0
def fake_exc_info(exc_info, filename, lineno):
    """Helper for `translate_exception`."""
    exc_type, exc_value, tb = exc_info

    # figure the real context out
    if tb is not None:
        locals = get_jinja_locals(tb.tb_frame.f_locals)

        # if there is a local called __jinja_exception__, we get
        # rid of it to not break the debug functionality.
        locals.pop('__jinja_exception__', None)
    else:
        locals = {}

    # assamble fake globals we need
    globals = {
        '__name__': filename,
        '__file__': filename,
        '__jinja_exception__': exc_info[:2],

        # we don't want to keep the reference to the template around
        # to not cause circular dependencies, but we mark it as Jinja
        # frame for the ProcessedTraceback
        '__jinja_template__': None
    }

    # and fake the exception
    code = compile('\n' * (lineno - 1) + raise_helper, filename, 'exec')

    # if it's possible, change the name of the code.  This won't work
    # on some python environments such as google appengine
    try:
        if tb is None:
            location = 'template'
        else:
            function = tb.tb_frame.f_code.co_name
            if function == 'root':
                location = 'top-level template code'
            elif function.startswith('block_'):
                location = 'block "%s"' % function[6:]
            else:
                location = 'template'

        if PY2:
            code = CodeType(0, code.co_nlocals, code.co_stacksize,
                            code.co_flags, code.co_code, code.co_consts,
                            code.co_names, code.co_varnames, filename,
                            location, code.co_firstlineno, code.co_lnotab, (),
                            ())
        else:
            code = CodeType(0, code.co_kwonlyargcount, code.co_nlocals,
                            code.co_stacksize, code.co_flags, code.co_code,
                            code.co_consts, code.co_names, code.co_varnames,
                            filename, location, code.co_firstlineno,
                            code.co_lnotab, (), ())
    except Exception as e:
        pass

    # execute the code and catch the new traceback
    try:
        exec(code, globals, locals)
    except:
        exc_info = sys.exc_info()
        new_tb = exc_info[2].tb_next

    # return without this frame
    return exc_info[:2] + (new_tb, )
コード例 #24
0
def inline(pre_func: FunctionType, func: FunctionType,
           pre_func_arguments: dict):
    """Insert `prefunc` at the beginning of `func` and return the corresponding
    function.

    `pre_func` should not have a return statement (else a ValueError is raised).
    `pre_func_arguments` keys should be identical as `pre_func` arguments names else a
    TypeError is raised.

    This approach takes less CPU instructions than the standard decorator approach.

    Example:

    def pre_func(b, c):
        a = "hello"
        print(a + " " + b + " " + c)

    def func(x, y):
        z = x + 2 * y
        return z ** 2

    The returned function corresponds to:

    def inlined(x, y):
        a = "hello"
        print(a)
        z = x + 2 * y
        return z ** 2
    """

    new_func = FunctionType(
        func.__code__,
        func.__globals__,
        func.__name__,
        func.__defaults__,
        func.__closure__,
    )

    if not has_no_return(pre_func):
        raise ValueError("`pre_func` returns something")

    pinned_pre_func = pin_arguments(pre_func, pre_func_arguments)
    pinned_pre_func_code = pinned_pre_func.__code__
    pinned_pre_func_co_consts = pinned_pre_func_code.co_consts
    pinned_pre_func_co_names = pinned_pre_func_code.co_names
    pinned_pre_func_co_varnames = pinned_pre_func_code.co_varnames
    pinned_pre_func_instructions = tuple(get_instructions(pinned_pre_func))
    pinned_pre_func_instructions_without_return = pinned_pre_func_instructions[:
                                                                               -2]

    func_code = func.__code__
    func_co_consts = func_code.co_consts
    func_co_names = func_code.co_names
    func_co_varnames = func_code.co_varnames

    func_instructions = tuple(get_instructions(func))
    shifted_func_instructions = shift_instructions(
        func_instructions,
        len(b"".join(pinned_pre_func_instructions_without_return)))

    new_co_consts = remove_duplicates(func_co_consts +
                                      pinned_pre_func_co_consts)
    new_co_names = remove_duplicates(func_co_names + pinned_pre_func_co_names)
    new_co_varnames = remove_duplicates(func_co_varnames +
                                        pinned_pre_func_co_varnames)

    trans_co_consts = get_transitions(pinned_pre_func_co_consts, new_co_consts)
    trans_co_names = get_transitions(pinned_pre_func_co_names, new_co_names)
    trans_co_varnames = get_transitions(pinned_pre_func_co_varnames,
                                        new_co_varnames)

    transitions = {
        **get_b_transitions(trans_co_consts, OpCode.LOAD_CONST, OpCode.LOAD_CONST),
        **get_b_transitions(trans_co_names, OpCode.LOAD_GLOBAL, OpCode.LOAD_GLOBAL),
        **get_b_transitions(trans_co_names, OpCode.LOAD_METHOD, OpCode.LOAD_METHOD),
        **get_b_transitions(trans_co_names, OpCode.LOAD_ATTR, OpCode.LOAD_ATTR),
        **get_b_transitions(trans_co_names, OpCode.STORE_ATTR, OpCode.STORE_ATTR),
        **get_b_transitions(trans_co_varnames, OpCode.LOAD_FAST, OpCode.LOAD_FAST),
        **get_b_transitions(trans_co_varnames, OpCode.STORE_FAST, OpCode.STORE_FAST),
    }

    new_pinned_pre_func_instructions = tuple(
        transitions.get(instruction, instruction)
        for instruction in pinned_pre_func_instructions_without_return)

    new_instructions = new_pinned_pre_func_instructions + shifted_func_instructions
    new_co_code = b"".join(new_instructions)

    nfcode = new_func.__code__

    python_version = sys.version_info

    if python_version.minor != 8:
        new_func.__code__ = CodeType(
            nfcode.co_argcount,
            nfcode.co_kwonlyargcount,
            len(new_co_varnames),
            nfcode.co_stacksize,
            nfcode.co_flags,
            new_co_code,
            new_co_consts,
            new_co_names,
            new_co_varnames,
            nfcode.co_filename,
            nfcode.co_name,
            nfcode.co_firstlineno,
            nfcode.co_lnotab,
            nfcode.co_freevars,
            nfcode.co_cellvars,
        )

        return new_func

    new_func.__code__ = CodeType(
        nfcode.co_argcount,
        nfcode.co_posonlyargcount,
        nfcode.co_kwonlyargcount,
        len(new_co_varnames),
        nfcode.co_stacksize,
        nfcode.co_flags,
        new_co_code,
        new_co_consts,
        new_co_names,
        new_co_varnames,
        nfcode.co_filename,
        nfcode.co_name,
        nfcode.co_firstlineno,
        nfcode.co_lnotab,
        nfcode.co_freevars,
        nfcode.co_cellvars,
    )

    return new_func
コード例 #25
0
ファイル: preprocess.py プロジェクト: fangchenli/zipline
def _build_preprocessed_function(func, processors, args_defaults, varargs,
                                 varkw):
    """
    Build a preprocessed function with the same signature as `func`.

    Uses `exec` internally to build a function that actually has the same
    signature as `func.
    """
    format_kwargs = {'func_name': func.__name__}

    def mangle(name):
        return 'a' + uuid4().hex + name

    format_kwargs['mangled_func'] = mangled_funcname = mangle(func.__name__)

    def make_processor_assignment(arg, processor_name):
        template = "{arg} = {processor}({func}, '{arg}', {arg})"
        return template.format(
            arg=arg,
            processor=processor_name,
            func=mangled_funcname,
        )

    exec_globals = {mangled_funcname: func, 'wraps': wraps}
    defaults_seen = 0
    default_name_template = 'a' + uuid4().hex + '_%d'
    signature = []
    call_args = []
    assignments = []
    star_map = {
        varargs: '*',
        varkw: '**',
    }

    def name_as_arg(arg):
        return star_map.get(arg, '') + arg

    for arg, default in args_defaults:
        if default is NO_DEFAULT:
            signature.append(name_as_arg(arg))
        else:
            default_name = default_name_template % defaults_seen
            exec_globals[default_name] = default
            signature.append('='.join([name_as_arg(arg), default_name]))
            defaults_seen += 1

        if arg in processors:
            procname = mangle('_processor_' + arg)
            exec_globals[procname] = processors[arg]
            assignments.append(make_processor_assignment(arg, procname))

        call_args.append(name_as_arg(arg))

    exec_str = dedent("""\
        @wraps({wrapped_funcname})
        def {func_name}({signature}):
            {assignments}
            return {wrapped_funcname}({call_args})
        """).format(
        func_name=func.__name__,
        signature=', '.join(signature),
        assignments='\n    '.join(assignments),
        wrapped_funcname=mangled_funcname,
        call_args=', '.join(call_args),
    )
    compiled = compile(
        exec_str,
        func.__code__.co_filename,
        mode='exec',
    )

    exec_locals = {}
    exec(compiled, exec_globals, exec_locals)
    new_func = exec_locals[func.__name__]

    code = new_func.__code__
    args = {
        attr: getattr(code, attr)
        for attr in dir(code) if attr.startswith('co_')
    }
    # Copy the firstlineno out of the underlying function so that exceptions
    # get raised with the correct traceback.
    # This also makes dynamic source inspection (like IPython `??` operator)
    # work as intended.
    try:
        # Try to get the pycode object from the underlying function.
        original_code = func.__code__
    except AttributeError:
        try:
            # The underlying callable was not a function, try to grab the
            # `__func__.__code__` which exists on method objects.
            original_code = func.__func__.__code__
        except AttributeError:
            # The underlying callable does not have a `__code__`. There is
            # nothing for us to correct.
            return new_func

    args['co_firstlineno'] = original_code.co_firstlineno
    new_func.__code__ = CodeType(*map(getitem(args), _code_argorder))
    return new_func
コード例 #26
0
#coding=utf-8
import dis
import opcode
from types import CodeType
"""
CodeType(
        argcount,             #   integer
        kwonlyargcount,       #   integer
        nlocals,              #   integer
        stacksize,            #   integer
        flags,                #   integer
        codestring,           #   bytes
        consts,               #   tuple
        names,                #   tuple
        varnames,             #   tuple
        filename,             #   string
        name,                 #   string
        firstlineno,          #   integer
        lnotab,               #   bytes
        freevars,             #   tuple
        cellvars              #   tuple
        )
"""


def code():
    return a + 1


dis.dis(code.__code__)
co_code = code.__code__.co_code
コード例 #27
0
ファイル: optimise.py プロジェクト: bigmlcom/pylibs
def _make_constants(
        function,
        builtins=None,
        builtin_only=False,
        stoplist=(),
        constant_fold=True,
        verbose=False,
):
    """Return the given ``function`` with its constants folded."""

    if verbose == 2:
        logging.info("# OPTIMISING : %s.%s", function.__module__,
                     function.__name__)

    co = function.func_code
    newcode = map(ord, co.co_code)
    newconsts = list(co.co_consts)
    names = co.co_names
    codelen = len(newcode)

    if builtins:
        env = vars(builtins).copy()
    else:
        env = vars(__builtin__).copy()

    if builtin_only:
        stoplist = dict.fromkeys(stoplist)
        stoplist.update(function.func_globals)
    else:
        env.update(function.func_globals)

    # first pass converts global lookups into constants

    i = 0

    while i < codelen:
        opcode = newcode[i]
        if opcode in (EXTENDED_ARG, STORE_GLOBAL):
            # for simplicity, only optimise common cases
            logging.info("\n\nFound opcode\n\n")
            return function
        if opcode == LOAD_GLOBAL:
            oparg = newcode[i + 1] + (newcode[i + 2] << 8)
            name = co.co_names[oparg]
            if name in env and name not in stoplist:
                value = env[name]
                for pos, v in enumerate(newconsts):
                    if v is value:
                        break
                else:
                    pos = len(newconsts)
                    newconsts.append(value)
                newcode[i] = LOAD_CONST
                newcode[i + 1] = pos & 0xFF
                newcode[i + 2] = pos >> 8
                if verbose:
                    logging.info("%s --> %s", name, value)
        i += 1
        if opcode >= HAVE_ARGUMENT:
            i += 2

    # second pass folds tuples of constants and constant attribute lookups

    if constant_fold:

        i = 0

        while i < codelen:

            newtuple = []
            while newcode[i] == LOAD_CONST:
                oparg = newcode[i + 1] + (newcode[i + 2] << 8)
                newtuple.append(newconsts[oparg])
                i += 3

            opcode = newcode[i]
            if not newtuple:
                i += 1
                if opcode >= HAVE_ARGUMENT:
                    i += 2
                continue

            if opcode == LOAD_ATTR:
                obj = newtuple[-1]
                oparg = newcode[i + 1] + (newcode[i + 2] << 8)
                name = names[oparg]
                try:
                    value = getattr(obj, name)
                except AttributeError:
                    continue
                deletions = 1

            elif opcode == BUILD_TUPLE:
                oparg = newcode[i + 1] + (newcode[i + 2] << 8)
                if oparg != len(newtuple):
                    continue
                deletions = len(newtuple)
                value = tuple(newtuple)

            else:
                continue

            reljump = deletions * 3
            newcode[i - reljump] = JUMP_FORWARD
            newcode[i - reljump + 1] = (reljump - 3) & 0xFF
            newcode[i - reljump + 2] = (reljump - 3) >> 8

            n = len(newconsts)
            newconsts.append(value)
            newcode[i] = LOAD_CONST
            newcode[i + 1] = n & 0xFF
            newcode[i + 2] = n >> 8

            i += 3

            if verbose:
                logging.info("New folded constant: %s", value)

    codestr = ''.join(map(chr, newcode))
    codeobj = CodeType(co.co_argcount,
                       co.co_nlocals, co.co_stacksize, co.co_flags, codestr,
                       tuple(newconsts), co.co_names, co.co_varnames,
                       co.co_filename, co.co_name, co.co_firstlineno,
                       co.co_lnotab, co.co_freevars, co.co_cellvars)

    return FunctionType(codeobj, function.func_globals, function.func_name,
                        function.func_defaults, function.func_closure)
コード例 #28
0
import marshal
from types import CodeType
c = CodeType(
    0, 0, 3, 30, 64,
    bytes([
        100, 0, 125, 0, 100, 1, 125, 1, 100, 2, 100, 3, 132, 0, 125, 2, 124, 0,
        100, 0, 107, 4, 114, 32, 116, 0, 100, 0, 131, 1, 1, 0, 124, 1, 100, 0,
        107, 4, 114, 48, 116, 0, 100, 5, 131, 1, 1, 0, 116, 0, 124, 2, 124, 0,
        124, 1, 131, 2, 124, 2, 100, 0, 100, 1, 131, 2, 23, 0, 131, 1, 1, 0,
        100, 6, 83, 0
    ]),
    (1, 2,
     CodeType(
         2, 0, 2, 30, 64,
         bytes([124, 0, 124, 1, 23, 0, 124, 0, 124, 1, 23, 0, 20, 0, 83, 0]),
         (), (), ("a", "b"), "qwe.py", "sum", 0, b'\x00', (),
         ()), "sum", ">", 123, None), ("print", ), ("a", "b", "sum"), "qwe.py",
    "<module>", 0, b'\x00', (), ())
x = marshal.dumps(c)
f = open('res.pyc', "wb+")
f.write(b'\x33\x0D\x0D\x0A')
f.write(b'\x8F\xB1\x21\x59')
f.write(b'\x69\x00\x00\x00')
f.write(x)
コード例 #29
0
ファイル: util.py プロジェクト: IPSW1/pyChecco
# noinspection PyProtectedMember
from bytecode import Instr, BasicBlock
from types import CodeType
from typing import List

from pyChecco.configuration import Configuration
from pyChecco.instrumentation.instruction_instrumentation import InstructionInstrumentation
from pyChecco.execution.executiontrace import ExecutionTrace
from pyChecco.execution.executiontracer import ExecutionTracer
from pyChecco.execution.testexecution.testexecutor import TestExecutor
from pyChecco.slicer.instruction import UniqueInstruction
from pyChecco.slicer.dynamic_slicer import DynamicSlicer, SlicingCriterion, DynamicSlice
from pyChecco.utils.pyc import Pyc

dummy_code_object = CodeType(0, 0, 0, 0, 0, 0, bytes(), (), (), (), "", "", 0, bytes())


def compare(dynamic_slice: List[UniqueInstruction], expected_slice: List[Instr]):
    expected_copy = expected_slice.copy()
    slice_copy = dynamic_slice.copy()

    for unique_instr in dynamic_slice:
        if isinstance(unique_instr.arg, BasicBlock) or isinstance(unique_instr.arg, CodeType) or \
                isinstance(unique_instr.arg, tuple):
            # Don't distinguish arguments for basic blocks, code objects and tuples
            jump_instr = _contains_name_argtype(expected_copy, unique_instr)
            try:
                expected_copy.remove(jump_instr)
                slice_copy.remove(unique_instr)
            except ValueError:
コード例 #30
0
ファイル: algorithm.py プロジェクト: jnhansen/nd
def wrap_algorithm(algo, name=None):
    """
    Return the function representation of an Algorithm derived class.

    NOTE: If algo.apply has ``*args`` and ``**kwargs`` parameters,
    this doesn't work.
    """
    if not issubclass(algo, Algorithm):
        raise ValueError('Class must be an instance of `nd.Algorithm`.')

    def _wrapper(*args, **kwargs):
        # First, apply the arguments to .apply():
        apply_kwargs = utils.extract_arguments(algo.apply, args, kwargs)
        init_args = apply_kwargs.pop('args', ())
        init_kwargs = apply_kwargs.pop('kwargs', {})
        return algo(*init_args, **init_kwargs).apply(**apply_kwargs)

    # Override function module
    _wrapper.__module__ = algo.__module__

    # Override position of source code to fix source code links in
    # documentation. This is probably a bad idea.
    code = _wrapper.__code__
    new_filename = inspect.getfile(algo)
    caller = inspect.getframeinfo(inspect.stack()[1][0])
    new_firstlineno = caller.lineno
    if PY_VERSION >= (3, 8):
        new_code = code.replace(
            co_filename=new_filename,
            co_firstlineno=new_firstlineno
        )
    else:
        new_code = CodeType(
            code.co_argcount,
            code.co_kwonlyargcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            new_filename,
            code.co_name,
            new_firstlineno,
            code.co_lnotab,
            code.co_freevars,
            code.co_cellvars
        )
    _wrapper.__code__ = new_code

    # Override function name
    if name is not None:
        _wrapper.__name__ = name

    # Override signature
    sig_init = inspect.signature(algo.__init__)
    sig_apply = inspect.signature(algo.apply)
    parameters = tuple(sig_apply.parameters.values())[1:] + \
        tuple(sig_init.parameters.values())[1:]
    # Sort parameters:
    # 1) put variadic parameters last
    # 2) put arguments without defaults first
    parameters = sorted(
        parameters,
        key=lambda p: (p.kind, p.default is not inspect._empty)
    )
    new_parameters = []
    for p in parameters:
        if p not in new_parameters:
            new_parameters.append(p)
    sig = sig_init.replace(parameters=new_parameters)
    _wrapper.__signature__ = sig

    # Override docstring
    link = ':class:`{}.{}`'.format(algo.__module__, algo.__name__)
    doc = utils.parse_docstring(algo.__doc__)
    doc[None].insert(0, "Wrapper for {}.".format(link))
    doc[None].insert(1, "")
    if algo.apply.__doc__ is not None:
        apply_doc = utils.parse_docstring(algo.apply.__doc__)
        if 'Parameters' in apply_doc:
            if 'Parameters' not in doc:
                doc['Parameters'] = apply_doc['Parameters']
            else:
                doc['Parameters'] = apply_doc['Parameters'] + doc['Parameters']
        if 'Returns' in apply_doc:
            doc['Returns'] = apply_doc['Returns']
    _wrapper.__doc__ = utils.assemble_docstring(doc, sig=sig)

    return _wrapper