0

I am trying to create a module and run it all from a string but I get an exception:

File "<frozen importlib._bootstrap>", line 568, in module_from_spec
AttributeError: 'str' object has no attribute 'loader'

My attempt:

from importlib.util import module_from_spec

task_string = """
print ('Hello world!')        
        """
module = module_from_spec("module_name")
exec(task_string, module.__dict__)

I know that I can use eval(task_string) but I wanted to run task_string in a sandbox, in other words, it would not access other variables in this scope. Thank you.

2
  • If restricting access to the current scope's variables is your only reason for using the module approach, it's worth noting that you can do that with the two optional arguments to exec. Commented Jun 12, 2018 at 5:32
  • @jedwards can you please provide an example? Thank you Commented Jun 12, 2018 at 5:33

1 Answer 1

1

Re: discussion in comments:

Consider this example:

var = "123"

code = "print(var)"

exec(code)

Calling exec like this will execute the string in the current scope, so it'll have access to your var and will print "123".

But you can restrict eval's context by specifying dictionaries that should be used as the globals and locals respectively:

var = "123"

code = "print(var)"

sandbox_globals = {}    
sandbox_locals = {}

exec(code, sandbox_globals, sandbox_locals)

Here, an exception will be raised:

NameError: name 'var' is not defined

Because you've specified the globals and locals to be used.

You can explicitly allow exec access by something like:

sandbox_globals = {'var':var}

But, you haven't fully restricted the sandbox this way.

sandbox_locals = {}
sandbox_globals = {}

code = "print(2**8)"

exec(code, sandbox_globals, sandbox_locals)

This code will work without throwing, printing 256. print works, and comes from somewhere. This is because __builtins__ is automatically added to sandbox_globals if you don't explicitly prevent that:

sandbox_locals = {}
sandbox_globals = {}

code = "print(2**8)"

sandbox_globals['__builtins__'] = {}

exec(code, sandbox_globals, sandbox_locals)

This will raise an Exception, since you're no longer providing print:

NameError: name 'print' is not defined
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.