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 __init__ files, only do something this import lib; lib.auto_import(__file__) <- this would search for python files in that folder where the __init__ 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 __init__ file is placed... How should I solve this? How should I change the search dir for from . statement?
Structure:
$ ls -R
.:
app.py lib x
./lib:
__init__.py auto_import.py
./x:
__init__.py y
./x/y:
__init__.py y.py
e.g.: ./x/y/__init__.py contains import lib; lib.auto_import(__file__)
auto_import is checking for files in dir of __file__ and import them with exec('from .{} import *') (but this from . is always the lib folder and not the dir of __file__, and that is my question, how to change this to dir of __file__
Of course the whole stuff is imported in app.py like:
import x
print(x.y)
Thanks
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__']:
continue
gns.update(__import__(item, gns, locals(), ['*'], 1).__dict__)
The problem of your approach is that auto_import is defined in lib/auto_import.py 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.
__import__Here is the auto_import script:
myimporter.py
# myimporter.py
def __import_siblings__(gns, lns={}):
for name in find_sibling_names(gns['__file__']):
gns.update((k,v) for k,v in __import__(name, gns,lns).__dict__.items() if not k.startswith('_'))
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(f.group(1) for f in files if f)
Inside your lib/x/y/__init__.py
#lib/x/y/__init__.py
from myimporter import __import_siblings__
__import_siblings__(globals())
Let's say you have a dummy module that need to be imported to y:
#lib/x/y/dummy.py
def hello():
print 'hello'
Test it:
import x.y
x.y.hello()
Please be aware that from lib import * is usually a bad habit because of namespace pollution. Use it with caution.
Refs: 1 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With