Skip to content
This repository has been archived by the owner on Mar 2, 2020. It is now read-only.

Commit

Permalink
plugin API - version 2.
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.fedorahosted.org/svn/suds/trunk@689 0b8c961e-115e-4cb0-8d11-a7d6dae58e8c
  • Loading branch information
jortel committed Aug 24, 2010
1 parent db02379 commit f8a959b
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 75 deletions.
3 changes: 3 additions & 0 deletions suds/bindings/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from suds.xsd.query import TypeQuery, ElementQuery
from suds.xsd.sxbasic import Element as SchemaElement
from suds.options import Options
from suds.plugin import PluginContainer
from copy import deepcopy

log = getLogger(__name__)
Expand Down Expand Up @@ -142,6 +143,8 @@ def get_reply(self, method, reply):
reply = self.replyfilter(reply)
sax = Parser()
replyroot = sax.parse(string=reply)
plugins = PluginContainer(self.options().plugins)
plugins.message.parsed(reply=replyroot)
soapenv = replyroot.getChild('Envelope')
soapenv.promotePrefixes()
soapbody = soapenv.getChild('Body')
Expand Down
33 changes: 18 additions & 15 deletions suds/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def __init__(self, url, **kwargs):
reader = DefinitionsReader(options, Definitions)
self.wsdl = reader.open(url)
plugins = PluginContainer(options.plugins)
plugins.initialized(wsdl=self.wsdl)
plugins.init.initialized(wsdl=self.wsdl)
self.factory = Factory(self.wsdl)
self.service = ServiceSelector(self, self.wsdl.services)
self.sd = []
Expand Down Expand Up @@ -624,10 +624,14 @@ def send(self, msg):
try:
self.last_sent(Document(msg))
plugins = PluginContainer(self.options.plugins)
plugins.sending(envelope=msg.root())
request = Request(location, str(msg))
plugins.message.marshalled(envelope=msg.root())
soapenv = str(msg)
plugins.message.sending(envelope=soapenv)
request = Request(location, soapenv)
request.headers = self.headers()
reply = transport.send(request)
ctx = plugins.message.received(reply=reply.message)
reply.message = ctx.reply
if retxml:
result = reply.message
else:
Expand Down Expand Up @@ -657,26 +661,25 @@ def succeeded(self, binding, reply):
Request succeeded, process the reply
@param binding: The binding to be used to process the reply.
@type binding: L{bindings.binding.Binding}
@param reply: The raw reply text.
@type reply: str
@return: The method result.
@rtype: I{builtin}, L{Object}
@raise WebFault: On server.
"""
log.debug('http succeeded:\n%s', reply)
plugins = PluginContainer(self.options.plugins)
ctx = plugins.received(reply=reply)
reply = ctx.reply
if len(reply) > 0:
r, p = binding.get_reply(self.method, reply)
self.last_received(r)
if self.options.faults:
return p
else:
return (200, p)
reply, result = binding.get_reply(self.method, reply)
self.last_received(reply)
else:
if self.options.faults:
return None
else:
return (200, None)
result = None
ctx = plugins.message.unmarshalled(reply=result)
result = ctx.reply
if self.options.faults:
return result
else:
return (200, result)

def failed(self, binding, error):
"""
Expand Down
2 changes: 1 addition & 1 deletion suds/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,6 @@ def __init__(self, **kwargs):
Definition('retxml', bool, False),
Definition('autoblend', bool, False),
Definition('cachingpolicy', int, 0),
Definition('plugins', [], (list, tuple)),
Definition('plugins', (list, tuple), []),
]
Skin.__init__(self, domain, definitions, kwargs)
160 changes: 115 additions & 45 deletions suds/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,81 +41,137 @@ class InitContext(Context):
pass


class LoadContext(Context):
class DocumentContext(Context):
"""
The XSD load context.
The XML document load context.
@ivar root: The loaded xsd document root.
@type root: L{sax.Element}
"""
pass


class InvokeContext(Context):
"""
The method invocaton context.
@ivar method: The name of the method.
@type method: str
@ivar params: The parameters passed.
@type params: list
@ivar params: The return object.
@type params: object
"""


class SendContext(Context):
class MessageContext(InvokeContext):
"""
The context for sending the soap envelope.
@ivar envelope: The soap envelope I{root} element to be sent.
@type envelope: L{sax.Element}
@ivar reply: The reply.
@type reply: (str|L{Element}|object)
"""
pass
class ReplyContext(Context):


class Plugin:
"""
The context for the text received as a reply
to method invocation.
@ivar reply: The received text.
@type reply: unicode
Plugin base.
"""
pass



class Plugin:
class InitPlugin(Plugin):
"""
The base class for suds plugins.
All plugins should implement this interface.
The base class for suds I{init} plugins.
"""

def initialized(self, context):
"""
Suds initialization.
Suds client initialization.
Called after wsdl the has been loaded. Provides the plugin
with the opportunity to inspect/modify the WSDL.
@param context: The init context.
@type context: L{InitContext}
"""
pass


class DocumentPlugin(Plugin):
"""
The base class for suds I{document} plugins.
"""

def parsed(self, context):
"""
Suds has parsed a WSDL/XSD document. Provides the plugin
with an opportunity to inspect/modify the parsed document.
Called after each WSDL/XSD document is parsed.
@param context: The document context.
@type context: L{LDocumentContext}
"""
pass


class MessagePlugin(Plugin):
"""
The base class for suds I{soap message} plugins.
"""

def loaded(self, context):
def marshalled(self, context):
"""
Suds has loaded an XSD document. Provides the plugin
with an opportunity to inspect/modify the loaded XSD.
Called after each XSD document is loaded.
@param context: The XSD load context.
@type context: L{LoadContext}
Suds will send the specified soap envelope.
Provides the plugin with the opportunity to inspect/modify
the envelope Document before it is sent.
@param context: The send context.
The I{envelope} is the envelope docuemnt.
@type context: L{MessageContext}
"""
pass

def sending(self, context):
"""
Suds will send the specified soap envelope.
Provides the plugin with the opportunity to inspect/modify
the message before it is sent.
the message text it is sent.
@param context: The send context.
@type context: L{SendContext}
The I{envelope} is the envelope text.
@type context: L{MessageContext}
"""
pass

def received(self, context):
"""
Suds has received the specified reply.
Provides the plugin with the opportunity to inspect/modify
the received XML.
the received XML text before it is SAX parsed.
@param context: The reply context.
The I{reply} is the raw text.
@type context: L{MessageContext}
"""
pass

def parsed(self, context):
"""
Suds has sax parsed the received reply.
Provides the plugin with the opportunity to inspect/modify
the sax parsed DOM tree for the reply.
@param context: The reply context.
The I{reply} is DOM tree.
@type context: L{MessageContext}
"""
pass

def unmarshalled(self, context):
"""
Suds has sax parsed the received reply.
Provides the plugin with the opportunity to inspect/modify
the unmarshalled reply.
@param context: The reply context.
@type context: L{ReplyContext}
The I{reply} is DOM tree.
@type context: L{MessageContext}
"""
pass


class PluginContainer:
"""
Expand All @@ -126,11 +182,10 @@ class PluginContainer:
@type ctxclass: dict
"""

ctxclass = {\
'initialized':InitContext,
'loaded':LoadContext,
'sending':SendContext,
'received':ReplyContext,
domain = {\
'init':InitContext,
'document':DocumentContext,
'message':MessageContext,
}

def __init__(self, plugins):
Expand All @@ -141,25 +196,40 @@ def __init__(self, plugins):
self.plugins = plugins

def __getattr__(self, name):
ctx = self.ctxclass.get(name)
ctx = self.domain.get(name)
if ctx:
return Method(name, ctx, self.plugins)
return PluginDomain(ctx, self.plugins)
else:
raise AttributeError(name)
raise Exception, 'plugin domain (%s), invalid' % name


class PluginDomain:
"""
The plugin domain.
@ivar ctx: A context.
@type ctx: L{Context}
@ivar plugins: A list of plugins (targets).
@type plugins: list
"""

def __init__(self, ctx, plugins):
self.ctx = ctx
self.plugins = plugins

def __getattr__(self, name):
return Method(name, self)


class Method:
"""
Plugin method.
@ivar name: The method name.
@type name: str
@ivar ctx: A context.
@type ctx: L{Context}
@ivar plugins: A list of plugins (targets).
@type plugins: list
@ivar domain: The plugin domain.
@type domain: L{PluginDomain}
"""

def __init__(self, name, ctx, plugins):
def __init__(self, name, domain):
"""
@param name: The method name.
@type name: str
Expand All @@ -169,16 +239,16 @@ def __init__(self, name, ctx, plugins):
@type plugins: list
"""
self.name = name
self.ctx = ctx()
self.plugins = plugins
self.domain = domain

def __call__(self, **kwargs):
self.ctx.__dict__.update(kwargs)
for plugin in self.plugins:
ctx = self.domain.ctx()
ctx.__dict__.update(kwargs)
for plugin in self.domain.plugins:
try:
method = getattr(plugin, self.name, None)
if method:
method(self.ctx)
method(ctx)
except Exception, pe:
log.exception(pe)
return self.ctx
return ctx
2 changes: 1 addition & 1 deletion suds/wsdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def __init__(self, url, options):
d = reader.open(url)
root = d.root()
plugins = PluginContainer(options.plugins)
plugins.loaded(root=root)
plugins.document.parsed(root=root)
WObject.__init__(self, root)
self.id = objid(self)
self.options = options
Expand Down
6 changes: 3 additions & 3 deletions suds/xsd/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from logging import getLogger
from suds.sax import splitPrefix, Namespace
from suds.sax.element import Element
from suds.plugin import Plugin
from suds.plugin import MessagePlugin

log = getLogger(__name__)

Expand Down Expand Up @@ -187,7 +187,7 @@ def exists(self, root):
return 0


class ImportDoctor(Doctor, Plugin):
class ImportDoctor(Doctor, MessagePlugin):
"""
Doctor used to fix missing imports.
@ivar imports: A list of imports to apply.
Expand All @@ -212,7 +212,7 @@ def examine(self, root):
for imp in self.imports:
imp.apply(root)

def loaded(self, context):
def parsed(self, context):
root = context.root
if Namespace.xsd(root.namespace()):
self.examine(root)
Expand Down
2 changes: 1 addition & 1 deletion suds/xsd/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def __init__(self, root, baseurl, options, container=None):
self.groups = {}
self.agrps = {}
plugins = PluginContainer(options.plugins)
plugins.loaded(root=root)
plugins.document.parsed(root=root)
if options.doctor is not None:
options.doctor.examine(root)
form = self.root.get('elementFormDefault')
Expand Down
Loading

0 comments on commit f8a959b

Please sign in to comment.