'Load and execute a full python script from a raw link?

I'm facing some problems trying to load a full python script from my pastebin/github pages.

I followed this link, trying to convert the raw into a temp file and use it like a module: How to load a python script from a raw link (such as Pastebin)?

And this is my test (Using a really simple python script as raw, my main program is not so simple unfortunately): https://trinket.io/python/0e95ba50c8

When I run the script (that now is creating a temp file in the current directory of the .py file) I get this error:

PermissionError: [Errno 13] Permission denied: 'C:\\Users\\BOT\\Images\\tempxm4xpwpz.py'

Otherwise I also treid the exec() function... No better results unfortunately. With this code:

import requests as rq
import urllib.request

def main():
    code = "https://pastebin.com/raw/MJmYEKqh"
    response = urllib.request.urlopen(code)
    data = response.read()
    exec(data)

I get this error:

  File "<string>", line 10, in <module>
  File "<string>", line 5, in hola
NameError: name 'printest' is not defined

Since my program is more complex compared to this simple test, I don't know how to proceed... Basically What I want to achieve is to write the full script of my program on GitHub and connect it to a .exe so if I upgrade the raw also my program is updated. Avoiding to generate and share (only with my friends) a new .exe everytime...

Do you think is possible? If so.. what am I doing wrong?

PS: I'm also open to other possibilities to let my friends update the program without downloading everytime the .exe, as soon as they don't have to install anything (that's why I'm using .exe).



Solution 1:[1]

Disclaimer: it is really not a good idea to run an unverified (let alone untrusted) code. That being said if you really want to do it...

Probably the easiest and "least-dirty" way would be to run whole new process. This can be done directly in python. Something like this should work (inspiration from the answer you linked in your question):

import urllib.request
import tempfile
import subprocess

code = "https://pastebin.com/raw/MJmYEKqh"
response = urllib.request.urlopen(code)
data = response.read()

with tempfile.NamedTemporaryFile(suffix='.py') as source_code_file:
    source_code_file.write(data)
    source_code_file.flush()
    subprocess.run(['python3', source_code_file.name])

You can also make your code with exec run correctly:

What may work:

  • exec(data, {}) -- All you need to do, is to supply {} as second argument (that is use exec(data, {})). Function exec may receive two additional optional arguments -- globals and locals. If you supply just one, it will use the same directory for locals. That is the code within the exec would behave like sort-of "clean" environment, at the top-level. Which is something you aim for.

  • exec(data, globals()) -- Second option is to supply the globals from your current scope. This will also work, though you probably has no need to give the execucted code access to your globals, given that that code will set-up everything inside anyway

What does not work:

  • exec(data, {}, {}) -- In this case the executed code will have two different dictionaries (albeit both empty) for locals and globals. As such it will behavie "as-in" (I'm not really sure about this part, but as I tested it, it seams as such) the function. Meaning that it will add the printest and hola functions to the local scope instead of global scope. Regardless, I expected it to work -- I expected it will just query the printest in the hola function from the local scope instead of global. However, for some reason the hola function in this case gets compiled in such a way it expects printest to be in global scope and not local, which is not there. I really did not figured out why. So this will result in the NameError

  • exec(data, globals(), locals()) -- This will provide access to the state from the caller function. Nevertheless, it will crash for the very same reason as in the previous case

  • exec(data) -- This is just a shorthand for exec(data, globals(), locals()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drecker