Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snoop doesn't load source code from compiled functions #28

Closed
vikt0rs opened this issue Dec 4, 2020 · 3 comments
Closed

Snoop doesn't load source code from compiled functions #28

vikt0rs opened this issue Dec 4, 2020 · 3 comments

Comments

@vikt0rs
Copy link

vikt0rs commented Dec 4, 2020

I'm trying to debug functions, generated from the source in runtime, but for some reason, snoop is unable to show the source code of such function. At the same time it shows variables and nested functions source - see an example below. Please, suggest, if I'm doing something wrong? Thanks!

Script output

    22:03:23.24 >>> Call to main in File "func_code", line 1
    22:03:23.24    1 | SOURCE IS UNAVAILABLE
    22:03:23.24    2 | SOURCE IS UNAVAILABLE
    22:03:23.24 ...... a = 2
    22:03:23.24    3 | SOURCE IS UNAVAILABLE
    22:03:23.24 ...... b = 3
    22:03:23.24    5 | SOURCE IS UNAVAILABLE
        22:03:23.33 >>> Call to Random.randint in File "/usr/local/Cellar/python@3.8/3.8.2/Frameworks/Python.framework/Versions/3.8/lib/python3.8/random.py", line 244
        22:03:23.33 .......... self = <random.Random object at 0x7ff952003810>
        22:03:23.33 .......... a = 1
        22:03:23.33 .......... b = 100
        22:03:23.33  244 |     def randint(self, a, b):
        22:03:23.34  248 |         return self.randrange(a, b+1)
        22:03:23.34 <<< Return value from Random.randint: 20
    22:03:23.34    5 | SOURCE IS UNAVAILABLE
    22:03:23.34 ...... c = 25
    22:03:23.34    7 | SOURCE IS UNAVAILABLE
    22:03:23.34 <<< Return value from main: 25

Script code

import types
import random

import snoop


func_text = """def main():
        a = 2
        b = 3
        c = a + b + random.randint(1, 100)
        return c"""

func_code = compile(
    source=func_text,
    filename="func_code",
    mode='exec',
)

tracer = snoop.snoop(depth=3)

func = types.FunctionType(
    func_code.co_consts[0],
    {
        "random": random,
        "tracer": tracer,
    },
    'func'
)


if __name__ == '__main__':
    with tracer:
        func()
@alexmojaki
Copy link
Owner

alexmojaki commented Dec 4, 2020

The source code is truly unavailable. It's not stored in the code object and Python doesn't know where to find it because func_code is not a real filename. If you raise an exception inside the compiled code, the traceback won't show the source code either.

You can create a real file, write func_text into it, and pass the actual filename to compile. If that's not an option, you can put the lines directly into the cache of the linecache module.

@vikt0rs
Copy link
Author

vikt0rs commented Dec 4, 2020

This sounds like a hack, but works! Thanks a lot for your help!

@alexmojaki
Copy link
Owner

alexmojaki commented Dec 4, 2020

You can also accomplish your main goal more elegantly with exec:

import random
import math
source = """
def main():
    print(random)
    print(math)
"""
code = compile(
    source=source,
    filename="<filename>",
    mode='exec',
)
globs = {"random": random}
exec(code, globs)
globs["main"]()

This prints the random module but fails on math because that wasn't included in the custom globals dictionary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants