relative imports with the __import__ function

C

Chris Colbert

I have package tree that looks like this:

main.py
package
----__init__.py
----configuration.ini
----server
--------__init__.py
--------xmlrpc_server.py
--------controller.py
--------reco
------------<irrelevant.py's>
----segmentation
--------__init__.py
--------red_objects.py
----<other irrelevant folders>


main.py launches an instance of xmlrpc_server.py which, in turn,
imports controller.py.
controller.py reads configuration.ini to determine which
module/function to import from the segmentation directory and
subsequently use.

that config file specifies the module as 'red_objects' and the
function as 'segment_red'.

I am trying to dynamically import that module and func using the
__import__ statement but keep getting empty module errors.

In the following code segment, the failing code is uncommented, but
the commented code works fine:

seg_mod = 'red_objects'
smod = __import__('..segmentation.%s' % seg_mod, fromlist=[seg_func], level=-1)

#from ..segmentation import red_objects
#smod = red_objects

I have tried all sorts of values for the 'level' kwarg as well as
everywhich variation of the dotted relative notation.

I'm assuming i'm missing something fundamental on the import resolution...

As an aside, I would like to move main.py inside of the package
directory, but I dont know if that is possible with what i'm trying to
do here.

Thanks for any help.

Cheers!

Chris
 
P

Peter Otten

Chris said:
I have package tree that looks like this:

main.py
package
----__init__.py
----configuration.ini
----server
--------__init__.py
--------xmlrpc_server.py
--------controller.py
--------reco
------------<irrelevant.py's>
----segmentation
--------__init__.py
--------red_objects.py
----<other irrelevant folders>


main.py launches an instance of xmlrpc_server.py which, in turn,
imports controller.py.
controller.py reads configuration.ini to determine which
module/function to import from the segmentation directory and
subsequently use.

that config file specifies the module as 'red_objects' and the
function as 'segment_red'.

I am trying to dynamically import that module and func using the
__import__ statement but keep getting empty module errors.

I'm assuming i'm missing something fundamental on the import resolution...

After some experimentation it turns out you have to provide some context for
__import__() to determine the absolute location of the requested module. The
required bit of information is the current module's __name__ attribute which
you can provide via the globals parameter:

def import_segmentation(name):
return getattr(__import__("segmentation." + name, level=2,
globals=globals()), name)

Peter
 
C

Chris Colbert

After some experimentation it turns out you have to provide some context for
__import__() to determine the absolute location of the requested module. The
required bit of information is the current module's __name__ attribute which
you can provide via the globals parameter:

def import_segmentation(name):
   return getattr(__import__("segmentation." + name, level=2,
globals=globals()), name)

Peter

Many thanks Peter!
Almost like a charm!

It seems the relative import level is dependent on the location of the
main entry module. I thought the whole idea of relative imports was to
make the import independent of the entry point?

here is the import function i'm using

def import_segmentation(self):
# get the segmentation function defined in configuration.ini
parent_dir = os.path.split(os.path.dirname(__file__))[0]
prsr = ConfigParser.ConfigParser()
prsr.read(os.path.join(parent_dir, 'configuration.ini'))
seg_mod = prsr.get('segmentation', 'module')
seg_func = prsr.get('segmentation', 'function')
print __name__
smod = __import__('segmentation.%s' % seg_mod, globals=globals(),
fromlist=[seg_func], level=2)
sfunc = getattr(smod, seg_func)
return sfunc

for that import level of 2 to work the tree must look like this:

main.py
package
----__init__.py
----configuration.ini
----server
--------__init__.py
--------xmlrpc_server.py
--------controller.py
--------reco
------------<irrelevant.py's>
----segmentation
--------__init__.py
--------red_objects.py
----<other irrelevant folders>

but if I rearrange the package structure like this (just moving the
location of main.py):

package
----main.py
----__init__.py
----configuration.ini
----server
--------__init__.py
--------xmlrpc_server.py
--------controller.py
--------reco
------------<irrelevant.py's>
----segmentation
--------__init__.py
--------red_objects.py
----<other irrelevant folders>

I have to change the import to level=1 or I get this error:
ValueError: Attempted relative import beyond toplevel package

I don't understand why the location of my main.py should have ANY
bearing on relative import resolution.

But again, i'm probably just being dense and need someone to explain
it to me in newb speak ;)

Cheers,

Chris
 
P

Peter Otten

Chris said:
It seems the relative import level is dependent on the location of the
main entry module. I thought the whole idea of relative imports was to
make the import independent of the entry point?

You don't have to specify it explicitly, so you can move a module containing

from .foo import bar

into another package without changing its source code (provided there is a
foo submodule with a bar attribute). This includes the trivial case of
renaming the parent package.

Of course Python has to know the importing module's location, just like you
cannot meet me one block north and three blocks west unless you know where I
currently am.

See also

http://www.python.org/dev/peps/pep-0328/#rationale-for-relative-imports

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top