chameleon chameleon - 1 year ago 53
Python Question

how to change relative import search path

I'm trying to create an auto_import function which is part of a library: the purpose of this to avoid listing

from .x import y
many times in
files, only do something this
import lib; lib.auto_import(__file__)
<- this would search for python files in that folder where the
is present and would import all stuff by exec statement (i.e.
exec('from .x import abc')

My problem is that, somehow the 'from' statement always tries to import .x from lib directory, even if I change the cwd to the directory where the actual
file is placed... How should I solve this? How should I change the search dir for
from .


$ ls -R
.: lib x


./x: y


import lib; lib.auto_import(__file__)

auto_import is checking for files in dir of
and import them with
exec('from .{} import *')
(but this from . is always the lib folder and not the dir of
, and that is my question, how to change this to dir of

Of course the whole stuff is imported in like:

import x


EDIT1: final auto_import (globals() / gns cannot be avoided )

import os, sys, inspect

def auto_import(gns):
current_frame = inspect.currentframe()
caller_frame = inspect.getouterframes(current_frame)[1]
src_file = caller_frame[1]
for item in os.listdir(os.path.dirname(src_file)):
item = item.split('.py')[0]

if item in ['__init__', '__pycache__']:

gns.update(__import__(item, gns, locals(), ['*'], 1).__dict__)

Answer Source

The problem of your approach is that auto_import is defined in lib/ so the context for exec('from .x import *') is always lib/. Even though you manage to fix the path problem, lib.auto_import(__file__) will not import anything to the namespace of lib.x.y, because the function locates in another module.

Use the built-in function __import__

Here is the auto_import script:

def __import_siblings__(gns, lns={}):
  for name in find_sibling_names(gns['__file__']):
    gns.update(__import__(name, gns,lns,['*'],1).__dict__)

import re,os
def find_sibling_names(filename):
  pyfp = re.compile(r'([a-zA-Z]\w*)\.py$')
  files = (pyfp.match(f) for f in os.listdir(os.path.dirname(filename)))
  return set( for f in files if f)

Inside your lib/x/y/

from myimporter import __import_siblings__

Let's say you have a dummy module that need to be imported to y:

def hello():
  print 'hello'

Test it:

import x.y

Please be aware that from lib import * is usually a bad habit because of namespace pollution. Use it with caution.