summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjortel <devnull@localhost>2010-08-24 14:42:24 +0000
committerjortel <devnull@localhost>2010-08-24 14:42:24 +0000
commit02882710fa81da1ed1c4d380f3be7c9fdf68a789 (patch)
tree87c1e7d12dfbadcf1a811d3fff763e0a591413ab
parent67dc0bbe2f44122c485d0bc7af903603757a18bb (diff)
downloadsuds-02882710fa81da1ed1c4d380f3be7c9fdf68a789.tar.gz
plugin API - version 2.
-rw-r--r--suds/bindings/binding.py3
-rw-r--r--suds/client.py33
-rw-r--r--suds/options.py2
-rw-r--r--suds/plugin.py160
-rw-r--r--suds/wsdl.py2
-rw-r--r--suds/xsd/doctor.py6
-rw-r--r--suds/xsd/schema.py2
-rw-r--r--tests/axis1.py36
8 files changed, 169 insertions, 75 deletions
diff --git a/suds/bindings/binding.py b/suds/bindings/binding.py
index ef857df..4a7a996 100644
--- a/suds/bindings/binding.py
+++ b/suds/bindings/binding.py
@@ -33,6 +33,7 @@ from suds.bindings.multiref import MultiRef
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__)
@@ -142,6 +143,8 @@ class Binding:
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')
diff --git a/suds/client.py b/suds/client.py
index 0bdde6f..d56cb99 100644
--- a/suds/client.py
+++ b/suds/client.py
@@ -111,7 +111,7 @@ class Client(object):
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 = []
@@ -624,10 +624,14 @@ class SoapClient:
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:
@@ -657,26 +661,25 @@ class SoapClient:
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):
"""
diff --git a/suds/options.py b/suds/options.py
index 36f1732..b4876d3 100644
--- a/suds/options.py
+++ b/suds/options.py
@@ -113,6 +113,6 @@ class Options(Skin):
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)
diff --git a/suds/plugin.py b/suds/plugin.py
index ca0826f..4cdb610 100644
--- a/suds/plugin.py
+++ b/suds/plugin.py
@@ -41,58 +41,90 @@ 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
@@ -100,9 +132,10 @@ class Plugin:
"""
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
@@ -110,12 +143,35 @@ class Plugin:
"""
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:
"""
@@ -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):
@@ -141,11 +196,28 @@ class PluginContainer:
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:
@@ -153,13 +225,11 @@ 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
@@ -169,16 +239,16 @@ class Method:
@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
diff --git a/suds/wsdl.py b/suds/wsdl.py
index 0400e9b..5115f4e 100644
--- a/suds/wsdl.py
+++ b/suds/wsdl.py
@@ -137,7 +137,7 @@ class Definitions(WObject):
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
diff --git a/suds/xsd/doctor.py b/suds/xsd/doctor.py
index 63271dc..700919c 100644
--- a/suds/xsd/doctor.py
+++ b/suds/xsd/doctor.py
@@ -22,7 +22,7 @@ schema(s).
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__)
@@ -187,7 +187,7 @@ class Import:
return 0
-class ImportDoctor(Doctor, Plugin):
+class ImportDoctor(Doctor, MessagePlugin):
"""
Doctor used to fix missing imports.
@ivar imports: A list of imports to apply.
@@ -212,7 +212,7 @@ class ImportDoctor(Doctor, Plugin):
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)
diff --git a/suds/xsd/schema.py b/suds/xsd/schema.py
index 912fb03..4d0ccdb 100644
--- a/suds/xsd/schema.py
+++ b/suds/xsd/schema.py
@@ -215,7 +215,7 @@ class Schema:
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')
diff --git a/tests/axis1.py b/tests/axis1.py
index 2206d02..3a0ebd4 100644
--- a/tests/axis1.py
+++ b/tests/axis1.py
@@ -29,7 +29,7 @@ from suds import WebFault
from suds.client import Client
from suds.sudsobject import Object
from suds.transport.https import HttpAuthenticated
-from suds.plugin import Plugin
+from suds.plugin import *
errors = 0
@@ -38,19 +38,37 @@ credentials = dict(username='jortel', password='abc123')
setup_logging()
-class TestPlugin(Plugin):
-
+class MyInitPlugin(InitPlugin):
+
def initialized(self, context):
- print 'initialized: ctx=%s' % context.__dict__
-
+ print 'PLUGIN (init): initialized: ctx=%s' % context.__dict__
+
+
+class MyDocumentPlugin(DocumentPlugin):
+
def loaded(self, context):
- print 'loaded: ctx=%s' % context.__dict__
+ print 'PLUGIN (document): loaded: ctx=%s' % context.__dict__
+
+
+class MyMessagePlugin(MessagePlugin):
+
+ def marshalled(self, context):
+ print 'PLUGIN (message): marshalled: ctx=%s' % context.__dict__
def sending(self, context):
- print 'sending: ctx=%s' % context.__dict__
+ print 'PLUGIN (message): sending: ctx=%s' % context.__dict__
def received(self, context):
- print 'received: ctx=%s' % context.__dict__
+ print 'PLUGIN (message): received: ctx=%s' % context.__dict__
+
+ def parsed(self, context):
+ print 'PLUGIN (message): parsed: ctx=%s' % context.__dict__
+
+ def unmarshalled(self, context):
+ print 'PLUGIN: (massage): unmarshalled: ctx=%s' % context.__dict__
+
+
+myplugins = (MyInitPlugin(), MyDocumentPlugin(), MyMessagePlugin(),)
#logging.getLogger('suds.client').setLevel(logging.DEBUG)
@@ -64,7 +82,7 @@ try:
url = 'http://localhost:8081/axis/services/basic-rpc-encoded?wsdl'
start(url)
t = HttpAuthenticated(**credentials)
- client = Client(url, transport=t, cache=None, plugins=[TestPlugin()])
+ client = Client(url, transport=t, cache=None, plugins=myplugins)
print client
#
# create a name object using the wsdl