7

I cant seem to list all derived classes using the __subclasses__() method. Here's my directory layout:

import.py
backends
      __init__.py
    --digger
          __init__.py
          base.py
          test.py
        --plugins
              plugina_plugin.py

From import.py i'm calling test.py. test.py in turn iterates over all the files in the plugins directory and loads all of them. test.py looks like this:

import os
import sys
import re

sys.path.append(os.path.join(os.path.abspath(os.path.dirname(os.path.abspath( __file__ )))))
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(os.path.abspath( __file__ ))), 'plugins'))

from base import BasePlugin

class TestImport:
    def __init__(self):
        print 'heeeeello'

        PLUGIN_DIRECTORY = os.path.join(os.path.abspath(os.path.dirname(os.path.abspath( __file__ ))), 'plugins')

        for filename in os.listdir (PLUGIN_DIRECTORY):
            # Ignore subfolders
            if os.path.isdir (os.path.join(PLUGIN_DIRECTORY, filename)):
                continue
            else:
                if re.match(r".*?_plugin\.py$", filename):
                    print ('Initialising plugin : ' + filename)
                    __import__(re.sub(r".py", r"", filename))

        print ('Plugin system initialized')
        print BasePlugin.__subclasses__()

The problem us that the __subclasses__() method doesn't show any derived classes. All plugins in the plugins directory derive from a base class in the base.py file.

base.py looks like this:

class BasePlugin(object):
    """
    Base
    """
    def __init__(self):
        pass

plugina_plugin.py looks like this:

from base import BasePlugin

class PluginA(BasePlugin):
    """
    Plugin A
    """
    def __init__(self):
        pass

Could anyone help me out with this? Whatm am i doing wrong? I've racked my brains over this but I cant seem to figure it out

Thanks.

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
  • Do you see the message `Initialising plugin : plugina_plugin`? – unutbu Jun 15 '10 at 19:42
  • Yeah. It pops up. It seems that the class even gets imported but the `__subclasses__` method doesn't list it for some reason. – Mridang Agarwalla Jun 15 '10 at 19:48
  • I haven't been able to reproduce the problem. `print BasePlugin.__subclasses__()` yields `[]`. Perhaps if you copy the directory structure and keep paring down the code to its simplest possible form (with each change testing if problem remains), at some intermediate stage you'll find a clue as to the source of the problem. For example, get rid of all extraneous code in test.py, simplify the directory structure, get rid of import.py, etc... – unutbu Jun 15 '10 at 20:12
  • 1
    What is your OS, and what is the python version? – John La Rooy Jun 15 '10 at 20:53

2 Answers2

7

There were no other base.py files. I'm on a WinXP (SP2) with Python 2.6. I added another class to my test.py file called PluginB which used BasePlugin as the base class. When i did

    print PluginA.__mro__
    print PluginB.__mro__

I got:

(<class 'plugina_plugin.PluginA'>, <class 'base.BasePlugin'>, <type 'object'>)
(<class 'backends.digger.test.PluginB'>, <class 'backends.digger.base.BasePlugin'>, <type 'object'>)

As you can see, they're both using the same base plugin but the qualified names are different. This was because in plugina_plugin.py I was importing BasePlugin like this:

from base import BasePlugin

Instead of:

from backends.digger.base import BasePlugin

Fixing this fixed it.

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
  • Thanks for digging through this issue! Who would've thought that an object with two different qualified names has two independent aliases! – advait Aug 30 '11 at 18:32
0

Perhaps the plugins are finding another base.py hiding somewhere (the plugin directory for example).
Run with python -v to see if two different base.py are getting imported

You can also look at PluginA.__mro__ and confirm that the BasePlugin in there is the right one

John La Rooy
  • 295,403
  • 53
  • 369
  • 502