2
import tempfile

tmp = tempfile.NamedTemporaryFile(delete=True)
try:
    # do stuff with temp
    tmp.write(b'def fun():\n\tprint("hello world!")\n')
    if __name__ == '__main__':
        func = __import__(tmp.name)
        func.fun()
finally:
    tmp.close()  # deletes the file

So I want to create a temporary file, add some source code to it and then import the module and call the function, but I always run into this error:

ModuleNotFoundError: No module named '/var/folders/3w/yyp887lx4018h9s5sr0bwhkw0000gn/T/tmp84bk0bic'

It doesn't seem to find the module of the temporary file. How do I solve this?

  • The temp module file probably is not in any directory mentioned in the `PYTHON_PATH`. How about putting the temp module file next to your main script file and importing it from there? That should be possible. – Alfe Jun 13 '18 at 12:13
  • @Alfe not sure how to do that, going to the docs to see how I can do that –  Jun 13 '18 at 12:14
  • 2
    Why write this stuff into a file instead of just `eval("your code here")`? – John Zwinck Jun 13 '18 at 12:21

2 Answers2

4

There are a few problems with your code:

  1. Your filename does not end with .py, but Python modules are expected to. You can fix this by setting suffix='.py' in NamedTemporaryFile().
  2. __import__() is not the right way to load a module from a full path. See here: How to import a module given the full path?
  3. You do not flush after writing and before importing, so even if Python does find the file, it may well be empty. Add tmp.flush() after writing to fix this.
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • according to @Alfe I created the file in the current directory as that of the script itself, I tried flushing too, I also gave a name to the file with `.py` extension, still getting the same error –  Jun 13 '18 at 12:32
  • @J.Doe: Are you still using `__import__()`? You should not. – John Zwinck Jun 13 '18 at 12:36
  • yeah I was at the time –  Jun 13 '18 at 13:10
1

Importing can only be done from certain directories which are part of the PYTHON_PATH. You can extend that. Then you will have to use __import__() with a module name (not a path in the file system). You will have to deal with the suffix for the temp file.

I implemented a simple version using the local directory for the temp module file and a version using a proper tempfile:

#!/usr/bin/env python3

import sys
import os
import tempfile

SCRIPT = '''\
def fun():
  print("hello world!")
'''

# simple version using the local directory:
with open('bla.py', 'w') as tmp_module_file:
  tmp_module_file.write(SCRIPT)
import bla
bla.fun()

# version using the tempfile module:    
tmpfile = tempfile.NamedTemporaryFile(suffix='.py', delete=True)
try:
  tmpfile.write(SCRIPT.encode('utf8'))
  tmpfile.flush()
  tmpmodule_path, tmpmodule_file_name = os.path.split(tmpfile.name)
  tmpmodule_name = tmpmodule_file_name[:-3]  # strip off the '.py'
  sys.path.append(tmpmodule_path)
  tmpmodule = __import__(tmpmodule_name)
finally:
  tmpfile.close()
tmpmodule.fun()
Alfe
  • 56,346
  • 20
  • 107
  • 159