In a previous post I mentioned importing a python file as a config file via ihooks.
Craig Ringer sent me a note, pasted below
I think there's a considerably simpler approach than the one you've taken, as well as an alternative to ihooks that's quite a bit tidier to use.
First, the simple alternative. The `import' statement pretty much just calls __builtin__.__import__(), and you're quite free to use that in your code directly. This lets you do something like this for your config importer (based off your posted code):
import os
import __builtin__
try:
config = __builtin__.__import__('config', globals(), {}, [])
except Exception:
# We catch any Exception because the user could do all sorts
# of things wrong in the import. We can't even guarantee that
# an ImportError comes from our __import__ call and not an import
# attempt inside the config file without delving into the backtrace
# using the traceback module.
print "An error occurred while importing the config file."
print "Traceback follows."
raise
def config_example():
print config.some_config_dictionary["option"]
if __name__ == "__main__":
config_example()
It's worth noting that if I recall correctly the \_\_builtin\_\_
should be used; \_\_builtins\_\_ is specific to the CPython
implementation.
If you start having to accept an explicit path for the config file
from the user or something then ihooks is probably better. For
simple cases, \_\_builtin\_\_.\_\_import\_\_() is much quicker and
easier to understand though.
If you do decide you need more than \_\_builtin\_\_.\_\_import\_\_()
has to offer, it may be better to look into the PEP 302 import
hooks, which are much cleaner and simpler than the rather ancient
ihooks module. I should probably submit a patch to the ihook docs to
make them refer to PEP 302, actually.
Some info on PEP 302:
`http://www.python.org/doc/2.3.5/whatsnew/section-pep302.html <http://www.python.org/doc/2.3.5/whatsnew/section-pep302.html>`__
Indeed, __import__ was my first attempt at doing what I wanted; but it is a little off the semantics I wanted. I wanted to be able to specify a file on the command line with an argument --config=/path/to/file/config.py and have that loaded in. For example, __import__("/path/to/config.py") doesn't work.
Import hooks I looked into and are a possibility, but these also don't quite give the semantics I wanted. Here's a minimal example of how it might work
import sys
import imp
import os
path_to_config_file = "./testdir/config.py"
class Config:
def __init__(self, path):
print path
self.path = path
def _get_code(self, fullname):
# path_to_config_file might have come in via our options, etc
f = open(path_to_config_file)
# read in the file and compile it
c = ""
for line in f.readlines():
c = c + line
code = compile(c, fullname, 'exec')
# false means this is not a package, code is the compiled code
return False, code
def find_module(self, fullname):
# sufficient to return ourselves
print fullname
return self
def load_module(self, fullname):
# get the code
ispkg, code = self._get_code(fullname)
# create a new module
mod = imp.new_module(fullname)
# add it to the modules list
sys.modules[fullname] = mod
# set the file
mod.__file__ = "<%s>" % (path_to_config_file)
# set the module loader
mod.__loader__ = self
# exec code
exec code in mod.__dict__
# return the module object
return mod
sys.path_hooks.append(Config)
import aconfigfile
print aconfigfile
aconfigfile.hello()
The issue I see with this is that the import aconfigfile isn't really clearly showing what I want. I really want to be able to pass any arbitrary file name to be imported, e.g. something like import ./a/config/config.file. As far as I can see, import hooks are more designed to import files held in, say, a zip or pak archive.