I have some code that loads a default configuration file and then allows users to supply their own Python files as additional supplemental configuration or overrides of the defaults:
# foo.py
def load(cfg_path=None):
# load default configuration
exec(default_config)
# load user-specific configuration
if cfg_path:
execfile(cfg_path)
There is a problem, though: execfile()
executes directives in the file specified by cfg_path
as if it were in the working directory of foo.py
, not its own working directory. Thus, import
directives might fail if the cfg_path
file does, say, from m import x
where m
is a module in the same directory as cfg_path
.
How do I execfile()
from the working directory of its argument, or otherwise achieve an equivalent result? Also, I've been told that execfile
is deprecated in Python 3 and that I should be using exec
, so if there's a better way that I should be doing this, I'm all ears.
Note: I don't think solutions which merely change the working directory are correct. That won't put those modules on the interpreter's module-lookup path, as far as I can tell.
os.chdir lets you change the working directory as you wish (you can extract the working directory of cfg_path
with os.path.dirname
); be sure to first get the current directory with os.getcwd if you want to restore it when you're done exec'ing cfg_path
.
Python 3 does indeed remove execfile
(in favor of a sequence where you read the file, compile
the contents, then exec
them), but you need not worry about that, if you're currently coding in Python 2.6, since the 2to3 source to source translation deals with all this smoothly and seamlessly.
Edit: the OP says, in a comment, that execfile
launches a separate process and does not respect the current working directory. This is false, and here's an example showing that it is:
import os
def makeascript(where):
f = open(where, 'w')
f.write('import os\nprint "Dir in file:", os.getcwd()\n')
f.close()
def main():
where = '/tmp/bah.py'
makeascript(where)
execfile(where)
os.chdir('/tmp')
execfile(where)
if __name__ == '__main__':
main()
Running this on my machine produces output such as:
Dir in file: /Users/aleax/stko
Dir in file: /private/tmp
clearly showing that execfile
does keep using the working directory that's set at the time execfile
executes. (If the file executed changes the working directory, that will be reflected after execfile
returns -- exactly because everything is taking place in the same process!).
So, whatever problems the OP is still observing are not tied to the current working directory (it's hard to diagnose what they may actually be, without seeing the code and the exact details of the observed problems;-).