FAQ
I'm trying to write some code which:
1. Finds all modules in a plugin directory
2. Imports those modules
3. Creates an instance of each object defined in the module (each module
will contain exactly 1 object, which is a subclass of 'Plugin')

The closest I've come so far is with something like:

In plugin.py:
# taken from http://docs.python.org/lib/built-in-funcs.html
def my_import(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod

def import_plugins():
mods = []
for filename in os.listdir('/plugins'):
if filename.endswith('.py'):
name = os.path.splitext(filename)[0]
mods.append(my_import('plugins.' + name))
return mods

class Plugin(object):
pass


In plugins/exampleplugin.py:
class ExamplePlugin(Plugin):
def __init__(self):
pass


Calling import_plugins() then gives me a list containing references to
modules.

How can I loop through that list and create an instance of whatever
object was defined within the module? (In this case I'd want to
construct an instance of ExamplePlugin)

Thanks in advance,
Dave


- --
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(
Dave Challis ) ><>
____dsc at ecs.soton.ac.uk_______________________(___________________________

Search Discussions

  • Diez B. Roggisch at Jul 22, 2008 at 12:42 pm

    Dave Challis wrote:

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    I'm trying to write some code which:
    1. Finds all modules in a plugin directory
    2. Imports those modules
    3. Creates an instance of each object defined in the module (each module
    will contain exactly 1 object, which is a subclass of 'Plugin')

    The closest I've come so far is with something like:

    In plugin.py:
    # taken from http://docs.python.org/lib/built-in-funcs.html
    def my_import(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
    mod = getattr(mod, comp)
    return mod

    def import_plugins():
    mods = []
    for filename in os.listdir('/plugins'):
    if filename.endswith('.py'):
    name = os.path.splitext(filename)[0]
    mods.append(my_import('plugins.' + name))
    return mods

    class Plugin(object):
    pass


    In plugins/exampleplugin.py:
    class ExamplePlugin(Plugin):
    def __init__(self):
    pass


    Calling import_plugins() then gives me a list containing references to
    modules.

    How can I loop through that list and create an instance of whatever
    object was defined within the module? (In this case I'd want to
    construct an instance of ExamplePlugin)

    Like this:

    for name in dir(plugin):
    thing = getattr(plugin, name)
    try:
    if issubclass(thing, Plugin):
    thing()
    except ValueError: # issubclass sucks
    pass

    Diez
  • Dave Challis at Jul 22, 2008 at 4:15 pm

    Diez B. Roggisch wrote:
    Dave Challis wrote:
    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    I'm trying to write some code which:
    1. Finds all modules in a plugin directory
    2. Imports those modules
    3. Creates an instance of each object defined in the module (each module
    will contain exactly 1 object, which is a subclass of 'Plugin')

    The closest I've come so far is with something like:

    In plugin.py:
    # taken from http://docs.python.org/lib/built-in-funcs.html
    def my_import(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
    mod = getattr(mod, comp)
    return mod

    def import_plugins():
    mods = []
    for filename in os.listdir('/plugins'):
    if filename.endswith('.py'):
    name = os.path.splitext(filename)[0]
    mods.append(my_import('plugins.' + name))
    return mods

    class Plugin(object):
    pass


    In plugins/exampleplugin.py:
    class ExamplePlugin(Plugin):
    def __init__(self):
    pass


    Calling import_plugins() then gives me a list containing references to
    modules.

    How can I loop through that list and create an instance of whatever
    object was defined within the module? (In this case I'd want to
    construct an instance of ExamplePlugin)

    Like this:

    for name in dir(plugin):
    thing = getattr(plugin, name)
    try:
    if issubclass(thing, Plugin):
    thing()
    except ValueError: # issubclass sucks
    pass

    Diez
    Thanks for that, it helped as a starting point. I had some trouble with
    using issubclass though (issubclass(Plugin, Plugin) returns true), which
    was complicating things.

    I modified your code to the following instead (which may well have it's
    own pitfalls I'm not aware of!):

    for name in dir(plugin):
    thing = getattr(plugin, name)
    if hasattr(thing, '__bases__') and \
    getattr(thing, '__bases__')[0] == Plugin:
    thing()

    Cheers,
    Dave


    - --
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    <> o ) <><
    . ( (
    ) Dave Challis <>< ) ) ><>
    _(__dsc at ecs.soton.ac.uk___________________________(____(__________________
  • Fredrik Lundh at Jul 22, 2008 at 4:28 pm

    Dave Challis wrote:

    Thanks for that, it helped as a starting point. I had some trouble with
    using issubclass though (issubclass(Plugin, Plugin) returns true), which
    was complicating things.

    I modified your code to the following instead (which may well have it's
    own pitfalls I'm not aware of!):

    for name in dir(plugin):
    thing = getattr(plugin, name)
    if hasattr(thing, '__bases__') and \
    getattr(thing, '__bases__')[0] == Plugin:
    thing()
    so now you're no longer supporting mixins and multiple-level
    inheritance? why not just tweak Diez' example a little:

    for name in dir(plugin):

    thing = getattr(plugin, name)

    # make sure this is a plugin
    try:
    if thing is Plugin:
    continue
    if not issubclass(thing, Plugin):
    continue
    except ValueError: # issubclass sucks
    continue # not a class

    thing() # probably needs error handling around this

    (I also moved the thing call out of the thing validation part, to allow
    you to distinguish between ValueErrors caused by issubclass and errors
    caused by things)

    (btw, another approach would be to use a metaclass to make Plugin
    classes register themselves on import)

    </F>
  • Dave Challis at Jul 25, 2008 at 11:27 am

    Fredrik Lundh wrote:
    so now you're no longer supporting mixins and multiple-level
    inheritance? why not just tweak Diez' example a little:

    for name in dir(plugin):

    thing = getattr(plugin, name)

    # make sure this is a plugin
    try:
    if thing is Plugin:
    continue
    if not issubclass(thing, Plugin):
    continue
    except ValueError: # issubclass sucks
    continue # not a class

    thing() # probably needs error handling around this

    (I also moved the thing call out of the thing validation part, to allow
    you to distinguish between ValueErrors caused by issubclass and errors
    caused by things)

    (btw, another approach would be to use a metaclass to make Plugin
    classes register themselves on import)

    </F>
    Thanks, that works much better. I've only been using python a couple of
    months, so still getting to grips with how it treats classes/subclasses.

    I'll have a look into metaclasses too, haven't stumbled upon those yet
    at all.

    Cheers,
    Dave

    - --
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ) <><
    <>< (
    Dave Challis )
    ____dsc at ecs.soton.ac.uk_______(___________________________________________
  • Fredrik Lundh at Jul 25, 2008 at 11:50 am

    Dave Challis wrote:

    I'll have a look into metaclasses too, haven't stumbled upon those yet
    at all.
    It's a potentially brain-exploding topic, though, so if the above
    solution works for you, you might want to leave it at that ;-)

    But very briefly, a metaclass is a something that's responsible for
    creating a class, much like an ordinary class is responsible for
    creating an object. When Python executes the following statement,

    class Spam:
    attrib = 1
    def func(self):
    pass
    # <-- end of class statement

    it will create a new scope for the class content, execute the class
    body, and then, when it reaches the end, call the "metaclass" to create
    the actual class object. The metaclass is given the requested name
    ("Spam" in this case), any base classes, and a dictionary containing
    everything from the class scope ("attrib" and "func", in this case).
    The thing that's returned is assigned to the "Spam" variable.

    The default metaclass ("type") just creates an ordinary class object,
    but if you replace that with your own metaclas, you can completely
    override that behaviour, or just extend it (e.g. by registering the
    subclasses in a common registry). Like, say, this:

    registry = [] # list of subclasses

    class Plugin(object):
    class __metaclass__(type):
    def __init__(cls, name, bases, dict):
    type.__init__(name, bases, dict)
    registry.append((name, cls))

    class SpamPlugin(Plugin):
    pass

    class BaconPlugin(Plugin):
    pass

    for name, cls in registry:
    if cls is not Plugin:
    print name, cls

    Here, the presence of an inner __metaclass__ class (which is a subclass
    of "type") causes Python's class machinery to use that class instead of
    "type" when creating class objects for Plugin or any subclass thereof.
    The extra code in the __init__ method just all plugins to a list.

    For more on this, see e.g.

    http://www.python.org/download/releases/2.2/descrintro/#metaclasses

    </F>
  • Kpd at Jul 29, 2008 at 1:51 pm

    On Jul 25, 7:50 am, Fredrik Lundh wrote:
    It's a potentially brain-exploding topic,
    -that you made very understandable. Thanks for posting that
    explanation and example.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJul 22, '08 at 11:09a
activeJul 29, '08 at 1:51p
posts7
users4
websitepython.org

People

Translate

site design / logo © 2022 Grokbase