Skip to content

Commit

Permalink
Adding Ducksoup module
Browse files Browse the repository at this point in the history
Signed-off-by: Ian Anderson <[email protected]>
  • Loading branch information
getfatday committed Sep 15, 2009
0 parents commit b0e41d7
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build/
dist/
*.egg-info/
*.pyc
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include README.textile
66 changes: 66 additions & 0 deletions README.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
h1. Ducksoup Module

A ducktype plugin library for python. The module does a "ducktype" interface check on a "setuptools":http://peak.telecommunity.com/DevCenter/setuptools
entry point module. If the module passes, it is listed as an available plugin.

_*{color:red;}Requires "setuptools":http://peak.telecommunity.com/DevCenter/setuptools*_

h2. Installing

Run the following shell commands:

<pre>
git clone git://github.com/getfatday/ducksoup.git
cd ducksoup
./setup.py install
</pre>

h2. Usage

Define a plugin interface and entry point for you application:

<pre>
# Define an interface.

class ICommand(IPlugin):

name = ""
description = ""
def execute(*arg): pass

# Register an entry point.

class Command(plugin):
__entry_point__ = "ducksoup.plugin.commands"
__interface__ = ICommand
</pre>

Register an external module as a plugin.

<pre>
from setuptools import setup

setup(
name="mycommands",
version="0.0.1",
description="""My Commands""",
entry_points="""
[ducksoup.plugin.commands]
mycommands.command = mycommands.command:Command
"""
)
</pre>

Search for available plugins:

<pre>

for entry in Command().entries:
print """Name: %s
Description: %s
""" % (entry.name, entry.description)
</pre>

h2. Feedback

Shoot me an email at "[email protected]":mailto:[email protected] with any feedback.
9 changes: 9 additions & 0 deletions ducksoup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""ducksoup
A ducktype plugin library for python. The module does a "ducktype" interface check on a "setuptools":http://peak.telecommunity.com/DevCenter/setuptools
entry point module. If the module passes, it is listed as an available plugin.
"""

__version__ = '0.0.1'
__dist__ = 'git://github.com/getfatday/ducksoup.git'

37 changes: 37 additions & 0 deletions ducksoup/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env python
# encoding: utf-8
"""
interface.py
Created by Ian Anderson on 2009-07-08.
Derived from:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/204349
http://svn.pythonfr.org/public/pythonfr/plugin_framework/framework
"""

import inspect

class interface_type(type):
"""
Validates the presence of required attributes
"""

def __new__(cls, classname, bases, classdict):
obj = type.__new__(cls, classname, bases, classdict)
interface = classdict.get('__implements__')

if interface:
defined = set(dir(obj))
required = set(dir(interface))
if not required.issubset(defined):
missing = list(required - defined)
error = "Not implemented methods from %s : %r"
raise KeyError, error % (interface.__name__, missing)

return obj


class interface(object):
__metaclass__ = interface_type
__implements__ = None
62 changes: 62 additions & 0 deletions ducksoup/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python
# encoding: utf-8
"""
plugin.py
Created by Ian Anderson on 2009-07-08.
"""

from interface import interface
from pkg_resources import iter_entry_points

class IPlugin():
# Returns true if plugin is enabled
def enabled(self): pass

class plugin_type(type):

def __init__(cls, classname, bases, classdict):
super(plugin_type, cls).__init__(classname, bases, classdict)
setattr(cls, '__entries__', None)
setattr(cls, '__invalid__', None)

class plugin(object):

__metaclass__ = plugin_type
__entry_point__ = "ducksoup.plugin"
__interface__ = IPlugin

@classmethod
def enabled(cls):
return True

@property
def entries(self):
if self.__entries__ == None:
self.__getentries__()
return self.__entries__

@property
def invalid_entries(self):
if self.__invalid__ == None:
self.__getentries__()
return self.__invalid__

def __getentries__(self):
"""Returns plugin classes avialable"""

self.__entries__ = []
self.__invalid__ = []

for e in iter_entry_points(group=self.__entry_point__):
cls = e.load()
defined = set(dir(cls))
required = set(dir(self.__interface__))
if not required.issubset(defined):
self.__invalid__.append(cls)
missing = list(required - defined)
error = "Plug-in '%s' missing implementations of '%s' required for '%s'"
print error % (cls.__name__, ", ".join(missing), self.__entry_point__)
else:
if cls.enabled():
self.__entries__.append(cls)
20 changes: 20 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python
# encoding: utf-8

"""
Created by Ian Anderson on 2009-09-15.
"""

from setuptools import setup
from ducksoup import __version__ as version
from ducksoup import __doc__ as long_description

setup(name = "ducksoup",
version = version,
description = "A ducktype plugin library for python",
author = "Ian Anderson",
author_email = "[email protected]",
url = "http://github.com/getfatday/ducksoup",
packages = ['ducksoup',],
long_description = long_description
)

0 comments on commit b0e41d7

Please sign in to comment.