import module by filename

Steven D. Majewski (sdm7g@elvis.med.virginia.edu)
Tue, 22 Mar 1994 18:41:17 -0500

Way Back, we had some discussion about the desire for changes or
options to 'import' - either to import using an explicit path,
bypassing the sys.path search sequence, or to import a module
under a different name. Several others joined me in the opinion
that it was a desirable feature, but we didn't come to any agreement
on a syntax change to import to enable this feature.

While working on a completely unrelated problem, I happened to
stumble on the discovery that NO CHANGES to import.c are necessary
to provide this functionality.

Here is a purely experimental demonstration:

Assumed: you must have a file named 'null_module.py' somewhere along PYTHONPATH.
This file should be empty. [ It will work if it's not empty, I
suppose, but there will be extra junk in the "virgin" module. ]

newmodule( modname ) imports this empty module, renames it, and deletes the
original name from sys.modules, so that it can be imported again.

importmodule( filename, modname ) create a newmodule with name
modname, and does an execfile on filename to 'source' the file
in the newmodule's namespace.

XXXX = importmodule( filename, 'XXXX' )
YYYY = importmodule( filename, 'YYYY' )

gives you two separate instances of the module defined in filename.

# ----- begin newmod.py
import sys

def newmodule( modname ):
import null_module
sys.modules[modname] = sys.modules['null_module']
sys.modules[modname].__name__ = modname
del sys.modules['null_module']
del null_module
return sys.modules[modname]

def importmodule( filename, modname ):
module = newmodule( modname )
execfile( filename, module.__dict__, module.__dict__ )
return module

# ----- end newmod.py

We wouldn't need the assignment if we can make sure we can enter
the module name into the correct module dictionary. ( i.e. we need
to know the value of module(__name__) in the CALLER's context, not
the module's context. )

If there is a clean way of doing that, then the 2nd arg can me made
optional, with the default being to separate the pathname parts and
construct the "usual" module name from an explicit pathname.

If it is also modified to take both explicit path names or to search
on PYTHONPATH, we can get all of the desired options out of this
function ( slightly modified. )

- Steve Majewski (804-982-0831) <sdm7g@Virginia.EDU>
- UVA Department of Molecular Physiology and Biological Physics

Below is a test file ( announce.py ) and the logged output
of a demonstration, importing the test file as two different modules.

# begin announce.py
#
#
print 'Hello There!!!!!' , __name__
#
#
z = 'Hello from ' + __name__
print z
Zdir = dir()
Zdir
def me( *args ):
for each_arg in args:
print each_arg
if args : return args
else: return None
me
#
for x in dir():
print '<', x, '>'

#
# end announce.py

$ python
Python 1.0.1 (Mar 15 1994)
Copyright 1991-1994 Stichting Mathematisch Centrum, Amsterdam
>>> from newmod import *
>>> dir()
['__name__', 'importmodule', 'newmodule', 'sys']
>>> XXXX = importmodule( 'announce.py', 'XXXX' )
Hello There!!!!! XXXX
Hello from XXXX
['__name__', 'z']
<function me at 20074288>
< Zdir >
< __name__ >
< me >
< z >
>>> XXXX
<module 'XXXX'>
>>> YYYY = importmodule( 'announce.py', 'YYYY' )
Hello There!!!!! YYYY
Hello from YYYY
['__name__', 'z']
<function me at 20074598>
< Zdir >
< __name__ >
< me >
< z >
>>> YYYY
<module 'YYYY'>
>>> XXXX.z
'Hello from XXXX'
>>> YYYY.z
'Hello from YYYY'
>>> XXXX == YYYY # the modules are not Eq objects
0
>>> XXXX.me == YYYY.me # and their contents are not Eq objects
0 # unless they are compared by value.
>>>