def _create_program(f, namespaces=None, constants=None, namespace=None):
    """
    f must be a callable.

    namespaces must be a sequence.  Each element must be a module,
    or the string '<math.h>'.

    constants must be dictionary of name, value pairs for constants
    that will be used in the function. (XXX It should be possible for
    this to be done automatically...)

    """

    if namespaces is None:
        namespaces = []
    if constants is None:
        constants = {}
    program_table = []
    # num_func_pushes = 0
    # num_data_pushes = 0
    bc = dis.Bytecode(f)

    if namespace is not None:
        # This initial loop is just a test of an idea.  It doesn't
        # yet have any effect on what follows afterwards.
        found_names = []
        current_name = None
        for pc, instruction in enumerate(bc):
            if instruction.opname == 'LOAD_GLOBAL':
                if current_name is not None:
                    found_names.append(current_name)
                current_name = [instruction.argval]
            elif instruction.opname == 'LOAD_ATTR':
                assert current_name is not None
                current_name.append(instruction.argval)
            elif instruction.opname in ['LOAD_METHOD', 'LOAD_FUNCTION']:
                current_name.append(instruction.argval)
                found_names.append(current_name)
                current_name = None
            else:
                if current_name is not None:
                    found_names.append(current_name)
                    current_name = None
        print("Found these names:")
        print(found_names)
        found_objects = []
        for found_name in found_names:
            top = found_name[0]
            if top not in namespace:
                if top not in c99math:
                    raise NameError('name %r is not defined' % top)
                if len(found_name) > 1:
                    raise AttributeError(f'C99 math function {top} has no '
                                         f'attribute {found_name[2]}')
                obj = ('<math.h>', top)
            else:
                obj = namespace[top]
                attrs = found_name[1:][::-1]
                while attrs:
                    attr = attrs.pop()
                    obj = getattr(obj, attr)
            found_objects.append(obj)
        print("Found objects:", found_objects)

    for pc, instruction in enumerate(bc):
        # instruction is a *Python* bytecode instruction (as represented by
        # dis.Bytecode(f)).
        if instruction.opname in py_binary_opnames:
            program_table.append(
                (op.name_to_code[instruction.opname[7:]], 0, 0.0))
        elif instruction.opname in ['UNARY_POSITIVE', 'UNARY_NEGATIVE']:
            program_table.append((op.name_to_code[instruction.opname], 0, 0.0))
        elif instruction.opname == 'LOAD_GLOBAL':
            if instruction.argval in constants:
                program_table.append(
                    (op.PUSH_CONSTANT, 0, constants[instruction.argval]))
            else:
                # Anything else global is expected to be a function.
                funcname = instruction.argval
                found = False
                # Find the function.
                for namespace in namespaces:
                    # Special case check for <math.h>
                    if namespace == '<math.h>':
                        # Rename to corresponding name in C99 math.h
                        funcname2 = {
                            'minimum': 'fmin',
                            'maximum': 'fmax',
                            'min': 'fmin',
                            'max': 'fmax',
                            'arctan2': 'atan2'
                        }.get(funcname, funcname)
                        if funcname2 in c99math_d:
                            mathfuncindex, nargs = c99math_d[funcname2]
                            if nargs == 1:
                                program_table.append(
                                    (op.PUSH_FUNCTION, mathfuncindex, 0.0))
                                found = True
                                break
                            elif nargs == 2:
                                program_table.append(
                                    (op.PUSH_FUNCTION, mathfuncindex, 0.0))
                                found = True
                                break
                            elif nargs == 3:
                                program_table.append(
                                    (op.PUSH_FUNCTION, mathfuncindex, 0.0))
                                found = True
                                break
                            else:
                                raise RuntimeError('functions with more than '
                                                   '3 args not handled yet.')
                        else:
                            continue
                    else:
                        assert isinstance(namespace, types.ModuleType)
                        func = getattr(namespace, funcname)
                        if func is None:
                            continue
                        if not isinstance(func, np.ufunc):
                            raise RuntimeError('%r is not a ufunc.' % funcname)
                        if func.nout != 1:
                            raise RuntimeError("nout != 1 for "
                                               f"{instruction.opname}")
                        sigstr_d = 'd' * func.nin + '->d'
                        if sigstr_d not in func.types:
                            raise RuntimeError(f"{funcname} does not have a "
                                               f"loop for {sigstr_d}")
                        # This won't work--currently only handle <math.h>.
                        program_table.append((op.PUSH_FUNCTION, func, funcname,
                                              namespace.__name__))
                        found = True
                if not found:
                    raise NameError('name %r is not defined.' % funcname)
        elif instruction.opname == 'LOAD_CONST':
            program_table.append(
                (op.PUSH_CONSTANT, 0, float(instruction.argval)))
        elif instruction.opname == 'LOAD_FAST':
            program_table.append((op.PUSH_LOCAL, instruction.arg, 0.0))
        elif instruction.opname == 'STORE_FAST':
            program_table.append((op.STORE_LOCAL, instruction.arg, 0.0))
        elif instruction.opname == 'CALL_FUNCTION':
            program_table.append((op.CALL_FUNCTION, instruction.argval, 0.0))
        elif instruction.opname == 'COMPARE_OP':
            if instruction.argval == '<':
                program_table.append((op.COMPARE_LT, 0, 0.0))
            elif instruction.argval == '<=':
                program_table.append((op.COMPARE_LE, 0, 0.0))
            elif instruction.argval == '>':
                program_table.append((op.COMPARE_GT, 0, 0.0))
            elif instruction.argval == '>=':
                program_table.append((op.COMPARE_GE, 0, 0.0))
            elif instruction.argval == '==':
                program_table.append((op.COMPARE_EQ, 0, 0.0))
            elif instruction.argval == '!=':
                program_table.append((op.COMPARE_NE, 0, 0.0))
            else:
                raise RuntimeError('unknown comparison operator '
                                   f'{instruction.argval}')
        elif instruction.opname == 'JUMP_FORWARD':
            # Python's JUMP_FORWARD is a relative jump.  Convert that
            # to a ufunkify absolute jump.
            offset = instruction.arg // 2 + 1
            program_table.append((op.JUMP, pc + offset, 0.0))
        elif instruction.opname == 'POP_JUMP_IF_FALSE':
            dest = instruction.argval // 2
            program_table.append((op.JUMP_IF_FALSE, dest, 0.0))
        elif instruction.opname == 'POP_JUMP_IF_TRUE':
            dest = instruction.argval // 2
            program_table.append((op.JUMP_IF_TRUE, dest, 0.0))
        elif instruction.opname == 'RETURN_VALUE':
            program_table.append((op.RETURN, 0, 0.0))
        elif instruction.opname == 'STORE_FAST':
            program_table.append((op.STORE_LOCAL, 0, 0.0))
        else:
            raise RuntimeError('unhandled op %r' % instruction.opname)

    program_table = np.array(program_table, dtype=program_dtype)
    return program_table
Example #2
0
def collect_try_except_info(co, use_func_first_line=False):
    if not hasattr(co, 'co_lnotab'):
        return []

    if use_func_first_line:
        firstlineno = co.co_firstlineno
    else:
        firstlineno = 0

    try_except_info_lst = []
    stack_in_setup = []

    if sys.version_info[0] < 3:
        iter_in = _iter_as_bytecode_as_instructions_py2(co)
    else:
        iter_in = dis.Bytecode(co)
    iter_in = list(iter_in)

    op_offset_to_line = dict(dis.findlinestarts(co))
    bytecode_to_instruction = {}
    for instruction in iter_in:
        bytecode_to_instruction[instruction.offset] = instruction

    if iter_in:
        for instruction in iter_in:
            curr_op_name = instruction.opname

            if curr_op_name == 'SETUP_EXCEPT':
                try_except_info = TryExceptInfo(
                    _get_line(op_offset_to_line,
                              instruction.offset,
                              firstlineno,
                              search=True))
                try_except_info.except_bytecode_offset = instruction.argval
                try_except_info.except_line = _get_line(
                    op_offset_to_line,
                    try_except_info.except_bytecode_offset,
                    firstlineno,
                )

                stack_in_setup.append(try_except_info)

            elif curr_op_name == 'SETUP_FINALLY':
                # We need to collect try..finally blocks too to make sure that
                # the stack_in_setup we're using to collect info is correct.
                try_except_info = TryExceptInfo(_get_line(op_offset_to_line,
                                                          instruction.offset,
                                                          firstlineno,
                                                          search=True),
                                                is_finally=True)
                stack_in_setup.append(try_except_info)

            elif curr_op_name == 'RAISE_VARARGS':
                # We want to know about reraises and returns inside of except blocks (unfortunately
                # a raise appears to the debugger as a return, so, we may need to differentiate).
                if instruction.argval == 0:
                    for info in stack_in_setup:
                        info.raise_lines_in_except.append(
                            _get_line(op_offset_to_line,
                                      instruction.offset,
                                      firstlineno,
                                      search=True))

            elif curr_op_name == 'END_FINALLY':  # The except block also ends with 'END_FINALLY'.
                stack_in_setup[
                    -1].except_end_bytecode_offset = instruction.offset
                stack_in_setup[-1].except_end_line = _get_line(
                    op_offset_to_line,
                    instruction.offset,
                    firstlineno,
                    search=True)
                if not stack_in_setup[-1].is_finally:
                    # Don't add try..finally blocks.
                    try_except_info_lst.append(stack_in_setup[-1])
                del stack_in_setup[-1]

        while stack_in_setup:
            # On Py3 the END_FINALLY may not be there (so, the end of the function is also the end
            # of the stack).
            stack_in_setup[-1].except_end_bytecode_offset = instruction.offset
            stack_in_setup[-1].except_end_line = _get_line(op_offset_to_line,
                                                           instruction.offset,
                                                           firstlineno,
                                                           search=True)
            if not stack_in_setup[-1].is_finally:
                # Don't add try..finally blocks.
                try_except_info_lst.append(stack_in_setup[-1])
            del stack_in_setup[-1]

    return try_except_info_lst
Example #3
0
    (8, (0, 9, 2)),  # 2 bytes magic number, \r\n, 4 bytes UNIX timestamp
    (12, (3, 6)),  # added 4 bytes file size
    # bytes 4-8 are flags, meaning of 9-16 depends on what flags are set
    # bit 0 not set: 9-12 timestamp, 13-16 file size
    # bit 0 set: 9-16 file hash (SipHash-2-4, k0 = 4 bytes of the file, k1 = 0)
    (16, (3, 7)),  # inserted 4 bytes bit flag field at 4-8 
    # future version may add more bytes still, at which point we can extend
    # this table. It is correct for Python versions up to 3.9
]
header_size = next(s for s, v in reversed(header_sizes)
                   if sys.version_info >= v)

if _opt == "-py":
    _file = _files[1]
    code = open(_file, "r")
    bytecode = dis.Bytecode(code.read())
    code.close()

    for instruction in bytecode:
        print(instruction.opname, instruction.argval)

elif _opt == "-pyc":
    _file = _files[1]
    file = open(_file, "rb")
    bytecode = file.read(header_size)
    code = marshal.load(file)
    file.close()
    bytecode = dis.Bytecode(code)

    for instruction in bytecode:
        print(instruction.opname, instruction.argval)
Example #4
0
import dis
import socket


def func():
    sock = socket.socket()
    v = 20
    print(v)


print(dis.dis(func))
ds = dis.Bytecode(func)

for i in ds:
    if i.opname == 'LOAD_ATTR' and i.argval == 'socket':
        print('we found socket')

# SQL
# Таблица (отношение)
# Поле (столбец)
# Ключи (первичный, внешний)
# Связи между таблицами
#     Один к одному
#     Один ко многим
#     Многие ко многим
# Транзакция

# CREATE TABLE
# ALTER TABLE
# DROP TABLE
# SELECT
Example #5
0
def python_disassemble(code_text: str):
    """Disassemble the python code_text. This is a wrapper for `dis.dis`"""
    import dis

    return dis.Bytecode(code_text).dis()
Example #6
0
 def test_iteration(self):
     for obj in [_f, _C(1).__init__, "a=1", _f.__code__]:
         with self.subTest(obj=obj):
             via_object = list(dis.Bytecode(obj))
             via_generator = list(dis.get_instructions(obj))
             self.assertEqual(via_object, via_generator)
Example #7
0
 def test_info(self):
     self.maxDiff = 1000
     for x, expected in CodeInfoTests.test_pairs:
         b = dis.Bytecode(x)
         self.assertRegex(b.info(), expected)
Example #8
0
def print_py(filename):
    check_file_format(filename, '.py')
    bytecode = dis.Bytecode(open(filename).read())
    for instr in bytecode:
        print("{} {}".format(instr.opname, instr.argrepr))
Example #9
0
def print_str(code_string):
    compiled = compile(code_string, '<string>', 'exec')
    bytecode = dis.Bytecode(compiled)
    for instr in bytecode:
        print("{} {}".format(instr.opname, instr.argrepr))
Example #10
0
def get_bytecode(filename):
    with open(filename) as f:
        code = ast.parse(f.read())
        bytecode = dis.Bytecode(compile(code, '<string>', 'exec')).dis()
    return bytecode
Example #11
0
def GetFID(f):
    try:
        result = str(list(dis.Bytecode(f)))
    except:
        result = str(f)
    return hash(result)
  pprint.pprint({a:type(getattr(mod,a)) for a in dir(mod)})
  
foo = OCCT.BRepAlgoAPI.BRepAlgoAPI_BooleanOperation()
reader = STEPControl_Reader()
foo = reader.OneShape
foo = OCCT.gp.gp_Vec.__init__
pprint.pprint({a:repr(getattr(foo,a)) for a in dir(foo)})
print(str(OCCT.gp.gp_Vec.__init__.__name__))
print(OCCT.gp.gp_Vec({}))
print(OCCT.BRepBuilderAPI.BRepBuilderAPI_MakeFace(6))
'''

import dis
g = 7
transitive_dependency = 6
print(repr(str(dis.Bytecode(pprint.pprint).dis())))
print(type(globals()))

import pyocct_system
from pyocct_system import *
print(sys.argv)
initialize_system(globals())


def dependency_function():
    transitive_dependency
    pass


@run_if_changed
def test():
Example #13
0
    x: int
    y: int


@dataclasses.dataclass
class Pair:
    left: Point
    right: Point


def use(x: int, y: int):
    left = Point(x, y)
    right = Point(x + 10, y)

    pair = Pair(left, right)
    print(
        statistics.median(
            [pair.left.x, pair.left.y, pair.right.x, pair.right.y]))


dis.dis(use)
# print(dis.opmap)

for instruction in dis.Bytecode(use):
    # LOAD_GLOBAL 0 が Pointを指すってどうやってわかるんだろ?
    # 0 LOAD_GLOBAL 0 (Point)
    # 2 LOAD_FAST   0 (x)
    # 2 LOAD_FAST   1 (y)
    print("@", instruction.starts_line, instruction.opcode, instruction.opname,
          instruction.arg, instruction.argval, instruction.argrepr)
Example #14
0

def findvar(x, end):
    print(" \\Checking for var. \"" + x + "\"")
    for j in range(len(vars)):
        if vars[j][0] == x:
            print("  \\Found var. \"" + x + "\"")
            return j
    print("  \\Could not find var. \"" + x + "\" " + end,
          end=(len(end) < 1) * "\n")
    return -1


if len(sys.argv) > 2:
    inF, out = open(sys.argv[1], "r").read(), []
    i, m, d, n = 0, 0, [i for i in dis.Bytecode(inF)], inF.split("\n")
    while i < len(d):
        if d[i].starts_line != None and args != []:
            print("line: " + str(m) + " | " + n[m] + "\n" + str(pre) + "\n")
            args = []
            m += 1
        print(d[i])

        if d[i].opname == "LOAD_CONST":
            if not ("SUBSCR" in d[i + 1].opname):
                print("\\Found LOAD_CONST")
                if d[i].argval == None:
                    print(" \\Can't set argument to \"None\".")
                    if d[i].is_jump_target == True:
                        args.append(["jmp", d[i].argval])
                    else:
Example #15
0
 def test_source_line_in_disassembly(self):
     actual = dis.Bytecode(simple).dis()[:3]
     expected = '{:>3}'.format(simple.__code__.co_firstlineno)
     self.assertEqual(actual, expected)
     actual = dis.Bytecode(simple, first_line=350).dis()[:3]
     self.assertEqual(actual, '350')
Example #16
0
def print_bytecode(source):
    bc = dis.Bytecode(source)
    for x in bc:
        print_row([x.opname, x.argrepr])
Example #17
0
 def test_instantiation(self):
     for obj in [_f, _C(1).__init__, 'a=1', _f.__code__]:
         with self.subTest(obj=obj):
             b = dis.Bytecode(obj)
             self.assertIsInstance(b.codeobj, types.CodeType)
     self.assertRaises(TypeError, dis.Bytecode, object())
Example #18
0
# Python 字节码反汇编器
# https://docs.python.org/zh-cn/3/library/dis.html
import dis


def myfunc(alist):
    return len(alist)


# 显示 myfunc() 的反汇编
dis.dis(myfunc)

print("------------")
bytecode = dis.Bytecode(myfunc)
print(bytecode.dis())
for instr in bytecode:
    print(instr.opname)

print(dis.opname)
print(dis.opmap)
Example #19
0
 def test_explicit_first_line(self):
     actual = dis.Bytecode(outer, first_line=expected_outer_line)
     self.assertEqual(list(actual), expected_opinfo_outer)
Example #20
0
def bytecodesnippet():
    # Input to receive code snippet from user
    source_py = input('Enter code snippet!')
    # Method to generate bytecode
    print(dis.Bytecode(source_py).dis())
Example #21
0
 def test_disassembled(self):
     actual = dis.Bytecode(_f).dis()
     self.assertEqual(actual, dis_f)
Example #22
0
    def disassemble_built_in(self, co, classname=None, code_objects={}):
        # Container for tokens
        tokens = []
        customize = {}
        self.code = array('B', co.co_code)
        self.build_lines_data(co)
        self.build_prev_op()

        # Get jump targets
        # Format: {target offset: [jump offsets]}
        jump_targets = self.find_jump_targets()
        bytecode = dis.Bytecode(co)

        # self.lines contains (block,addrLastInstr)
        if classname:
            classname = '_' + classname.lstrip('_') + '__'

            def unmangle(name):
                if name.startswith(classname) and name[-2:] != '__':
                    return name[len(classname) - 2:]
                return name

            # free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ]
            # names = [ unmangle(name) for name in co.co_names ]
            # varnames = [ unmangle(name) for name in co.co_varnames ]
        else:
            # free = co.co_cellvars + co.co_freevars
            # names = co.co_names
            # varnames = co.co_varnames
            pass

        # Scan for assertions. Later we will
        # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT' for those
        # assertions
        self.load_asserts = set()
        bs = list(bytecode)
        n = len(bs)
        for i in range(n):
            inst = bs[i]
            if inst.opname == 'POP_JUMP_IF_TRUE' and i + 1 < n:
                next_inst = bs[i + 1]
                if (next_inst.opname == 'LOAD_GLOBAL'
                        and next_inst.argval == 'AssertionError'):
                    self.load_asserts.add(next_inst.offset)

        for inst in bytecode:
            if inst.offset in jump_targets:
                jump_idx = 0
                for jump_offset in jump_targets[inst.offset]:
                    tokens.append(
                        Token('COME_FROM',
                              None,
                              repr(jump_offset),
                              offset='%s_%s' % (inst.offset, jump_idx)))
                    jump_idx += 1
                    pass
                pass

            pattr = inst.argrepr
            opname = inst.opname

            if opname in ['LOAD_CONST']:
                const = inst.argval
                if iscode(const):
                    if const.co_name == '<lambda>':
                        opname = 'LOAD_LAMBDA'
                    elif const.co_name == '<genexpr>':
                        opname = 'LOAD_GENEXPR'
                    elif const.co_name == '<dictcomp>':
                        opname = 'LOAD_DICTCOMP'
                    elif const.co_name == '<setcomp>':
                        opname = 'LOAD_SETCOMP'
                    elif const.co_name == '<listcomp>':
                        opname = 'LOAD_LISTCOMP'
                    # verify() uses 'pattr' for comparison, since 'attr'
                    # now holds Code(const) and thus can not be used
                    # for comparison (todo: think about changing this)
                    # pattr = 'code_object @ 0x%x %s->%s' %\
                    # (id(const), const.co_filename, const.co_name)
                    pattr = '<code_object ' + const.co_name + '>'
                else:
                    pattr = const
                    pass
            elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET',
                            'BUILD_SLICE', 'UNPACK_SEQUENCE', 'MAKE_FUNCTION',
                            'MAKE_CLOSURE', 'DUP_TOPX', 'RAISE_VARARGS'):
                # if opname == 'BUILD_TUPLE' and \
                #     self.code[self.prev[offset]] == LOAD_CLOSURE:
                #     continue
                # else:
                #     op_name = '%s_%d' % (op_name, oparg)
                #     if opname != BUILD_SLICE:
                #         customize[op_name] = oparg
                opname = '%s_%d' % (opname, inst.argval)
                if inst.opname != 'BUILD_SLICE':
                    customize[opname] = inst.argval

            elif opname == 'JUMP_ABSOLUTE':
                pattr = inst.argval
                target = self.get_target(inst.offset)
                if target < inst.offset:
                    if (inst.offset in self.stmts
                            and self.code[inst.offset + 3]
                            not in (END_FINALLY, POP_BLOCK)
                            and offset not in self.not_continue):
                        opname = 'CONTINUE'
                    else:
                        opname = 'JUMP_BACK'

            elif inst.offset in self.load_asserts:
                opname = 'LOAD_ASSERT'

            tokens.append(
                Token(
                    type_=opname,
                    attr=inst.argval,
                    pattr=pattr,
                    offset=inst.offset,
                    linestart=inst.starts_line,
                ))
            pass
        return tokens, {}
Example #23
0
import dis


def hello_world():
    print('Hello World')


hello_world()

# dis.dis(hello_world)

print('Byte Code')
string = dis.Bytecode(hello_world)
for x in string:
    print(x)
Example #24
0
    if symbol not in code.co_names:
        # name's not there, can't possibly be an assignment
        return None

    name_idx = list(code.co_names).index(symbol)

    STORE_NAME = 90
    STORE_GLOBAL = 97
    LOAD_CONST = 100

    const = default

<<<<<<< HEAD
    for byte_code in Bytecode(code):
=======
    for byte_code in dis.Bytecode(code):
>>>>>>> 7e5c5fbd6c824de4d4c2b62da3f7cae87d462119
        op = byte_code.opcode
        arg = byte_code.arg

        if op == LOAD_CONST:
            const = code.co_consts[arg]
        elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
            return const
        else:
            const = default


def _update_globals():
    """
    Patch the globals to remove the objects not available on some platforms.
Example #25
0
def bytecodesnippet():
    source_py = input('Enter code snippet! ')
    print(dis.Bytecode(source_py).dis())
Example #26
0
    assert bool(matcher_pattern.match(ObjectPattern))
    # assert bool(matcher_pattern.match(ObjectMultiPattern))
    if hasattr(re, 'Pattern'):
        assert bool(matcher_pattern.match(re.Pattern))


if __name__ == '__main__':
    print(pyopm)
    import dis
    # test_start_end_block()
    print('== test_object_pattern_basic')
    test_object_pattern_basic()
    print('== test_object_special_cases')
    test_object_pattern_special_cases()
    #
    d = dis.Bytecode(test_object_pattern_context_handler)
    print(d.dis())
    print('names    GLOBAL : ', d.codeobj.co_names)
    print('varnames FAST   : ', d.codeobj.co_varnames)
    print('cellvars CLOSURE: ', d.codeobj.co_cellvars)
    print('freevars DEREF  : ', d.codeobj.co_freevars)
    #
    print('== test_object_context_handler')
    test_object_pattern_context_handler()
    print('== test_object_multi_pattern')
    test_basic_object_multi_pattern()
    print('== test_str_repr')
    test_str_repr()
    print('== test_context_handler')
    test_context_handler()
    print('== test_meta_match')
Example #27
0
 def __get_bytecode(self, filename):
     if os.path.exists(filename):
         func = open(filename).read()
         bytecode = dis.Bytecode(func)
         return bytecode
def find_the_secret(f):
    return dis.Bytecode(f).dis()[92:124]
Example #29
0
def method_complexity(method: Callable) -> float:
    """Estimate complexity of a method by counting bytecode instructions"""
    bytecode = dis.Bytecode(method).dis()
    return len([line for line in bytecode.splitlines() if line])
Example #30
0
 def fromfunction(cls, source_lines, f):
     """Construct a code package from the source code of an entire module and a code object of
        a function defined within that module.
     """
     return cls(f.co_name, source_lines, dis.Bytecode(f))