Commits

Anonymous committed 45296c4

plugin API - version 2.

  • Participants
  • Parent commits a8ebe53

Comments (0)

Files changed (8)

File suds/bindings/binding.py

 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__)
         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')

File suds/client.py

         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 = []
         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:
         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):
         """

File suds/options.py

             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)

File suds/plugin.py

     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):
-    """
-    The context for the text received as a reply
-    to method invocation.
-    @ivar reply: The received text.
-    @type reply: unicode
-    """
-    pass
-    
 
 
 class Plugin:
     """
-    The base class for suds plugins.
-    All plugins should implement this interface.
+    Plugin base.
+    """
+    pass
+
+
+class InitPlugin(Plugin):
+    """
+    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 loaded(self, context):
+    def parsed(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 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 marshalled(self, context):
+        """
+        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
     
         """
         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
     
         """
         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.
-        @type context: L{ReplyContext}
+            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.
+            The I{reply} is DOM tree.
+        @type context: L{MessageContext}
+        """
+        pass
+
     
 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):
         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
         @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

File suds/wsdl.py

         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

File suds/xsd/doctor.py

 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__)
 
         return 0
     
 
-class ImportDoctor(Doctor, Plugin):
+class ImportDoctor(Doctor, MessagePlugin):
     """
     Doctor used to fix missing imports.
     @ivar imports: A list of imports to apply.
         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)

File suds/xsd/schema.py

         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')

File tests/axis1.py

 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
 
 setup_logging()
 
 
-class TestPlugin(Plugin):
+class MyInitPlugin(InitPlugin):
+
+    def initialized(self, context):
+        print 'PLUGIN (init): initialized: ctx=%s' % context.__dict__
+
     
-    def initialized(self, context):
-        print 'initialized: ctx=%s' % context.__dict__
+class MyDocumentPlugin(DocumentPlugin):
+
+    def loaded(self, context):
+        print 'PLUGIN (document): loaded: ctx=%s' % context.__dict__
+
         
-    def loaded(self, context):
-        print '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)
     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