4

I want to pass my program a file and get a function out of it.

For example, I have a file, foo.py, who's location is not known until run time (it will be passed to to code by the command line or something like that), can be anywhere on my system and looks like this:

def bar():
    return "foobar"

how can I get my code to run the function bar?

If the location was known before run time I could do this:

import sys
sys.path.append("path_to_foo")
import foo

foo.bar()

I could create an init.py file in the folder where foo.py is and use importlib or imp but it seems messy. I can't use __import__ as I get ImportError: Import by filename is not supported.

R.Mckemey
  • 335
  • 1
  • 3
  • 14
  • 2
    "I could [...] use `importlib` [...] but it seems messy." You have to resort to messy solutions when you have messy problems. Why isn't `importlib` sufficient? – Vincent Savard May 18 '16 at 14:49
  • Also, you don't need a `__init__.py` file at all. In Py3, the more powerful `importlib` functions are _the_ correct way to import arbitrary files. In earlier Python, you can just add the folder containing `foo.py` to `sys.path`, then run `import foo` without using a special importing function at all. – ShadowRanger May 18 '16 at 14:56
  • Is foo.py in the same directory as your file? – NoOneIsHere May 18 '16 at 15:00
  • I'm using Python 2.7. I can't use `import foo` as I don't know the file name until run time. – R.Mckemey May 18 '16 at 15:04
  • I don't want to create an `init.py` file and leave it lying around, I could clean it up afterwards. I don't know how I can be sure to get rid of it but that's another topic. It just seems perverse that I have to create an empty file to do something. – R.Mckemey May 18 '16 at 15:13

3 Answers3

11

You could open the file and execute it using exec.

f = open('foo.py')
source = f.read()
exec(source)
print bar()

You could even look for the specific function using re

Enrique GR
  • 149
  • 4
  • I ended up using something like this. I actually did `sys.path.append("path_to_foo"); file_name = foo.py; exec(import file_name as foo); foo.bar()` – R.Mckemey May 18 '16 at 15:21
  • @R.Mckemey You said `who's location is not known until run time, can be anywhere on my system...`. How are you going to find the file? – NoOneIsHere May 18 '16 at 15:25
  • Sorry I was unclear, the whole file path will be passed to the program. I'll run it something like `python program.py path_to_foo/foo.py` – R.Mckemey May 18 '16 at 15:33
  • To be noted: I you try to put this in a function, you need to have your function return whatever functions or variables you are interested in and assign the result of the function call, otherwise, the functions and variables created by `exec(source)` will only live in the function scope. – bli Oct 10 '19 at 09:26
0

You can write a dummy function and call it everywhere you need, to bypass checking:

def bar():
    pass

at run-time override the function with the one you actually intend to, and automatically everywhere it will be used.

Note: This is more messy than using the importlib.

anand
  • 1,506
  • 14
  • 28
0

If foo.py is in the same directory as your main file, you can use

from . import foo

(Python 3). This works because . is the directory of your file, and Python will import files in the same directory for you. You can then use

foo.bar()

If it is not, you need to find it, and then execute it:

import os
from os.path import join

lookfor = "foo.py"
for root, dirs, files in os.walk('C:\\'): # or '/' for Linux / OSX
    if lookfor in files:
        execfile(join(root, lookfor)) # Python 2, or
        with open(join(root, lookfor)) as file:
            exec(''.join(file.readlines()))
        break
foo.bar()

Credits: Martin Stone. I did not just copy the code, I understand the code, and could've made it myself.

Community
  • 1
  • 1
NoOneIsHere
  • 1,054
  • 16
  • 28