I've been learning me some dynamic 'plugin loading' for python and noticed a not really problematic but rather an interesting difference between import module and from package import module.
I've created a test script consisting of four files (resembles my own setup for what I want to achieve)
The file tree looks like this:
- test (main package)
- sup (package, plugin folder)
- __init__.py
- uber.py (plugin)
- __init__.py
- bar.py ('main'-program)
- foo.py (object that needs dynamically added functionality)
- poo.py (decorator)
- sup (package, plugin folder)
poo.py:
from test import foo
def decorate(method):
print "before:", method.__name__ in dir(foo.Foo)
setattr(foo.Foo, method.__name__, method)
print "after :", method.__name__ in dir(foo.Foo)
return method
foo.py:
import os
class Foo(object):
def __init__(self):
self.__loadplugins("sup")
@classmethod
def __loadplugins(cls, plugindir):
for f in os.listdir(os.path.join(os.path.dirname(__file__), plugindir)):
if f.endswith(".py"):
__import__(("%s.%s" % (plugindir, f))[0:-3])
uber.py:
from test import poo
@poo.decorate
def aFunction(self, anArg):
print anArg
I have two versions of bar.py, this one does not work:
import foo
f = foo.Foo()
f.aFunction("print goes here") # pylint: disable-msg=E1101
This one does work:
from test import foo
f = foo.Foo()
f.aFunction("print goes here") # pylint: disable-msg=E1101
The only difference between the two bars is the import. One is relative the other one is not. But the relative one does not work, and the absolute one does work. Is there anyone who can replicate this on his machine and could give some kind of explanation of why it is happening?
update
Thought it would be useful to also note my python version:
Using normal python release 2.7.2 x86
update
Output of the 'wrong' bar.py:
before: False
after : True
Traceback (most recent call last):
File "C:\Users\Daan\workspace\python\mytests\src\test\bar.py", line 6, in <module>
f.aFunction("print goes here") # pylint: disable-msg=E1101
AttributeError: 'Foo' object has no attribute 'aFunction'
Output of the 'correct' bar.py:
before: False
after : True
print goes here
__init__.py