<div dir="ltr">Hello people,<div><br></div><div>I'm exposing some services as both SOAP and json.</div><div>I've read the docs on this and I know I can't 'reuse' the same MyService class in 2 applications. The recommended way is to create a generator function that then returns a copy of the class contained in it.</div><div><br></div><div>For a very stupid reason :-) (I don't get Sphinx autodocs for the method of the Service defined inside the generator function, and yes, it should be fixable in Sphinx config) I wondered if it was possible to use a different approach to do this, to get a generic 'spyne service factory'.</div><div>I first tried to subclass the ServiceBase-derived class and it didn't work (Metaclass is lost, I'd guess, but for these think I need to improve my Python knowledge ^^; ) <br><br>I ended up trying to deepcopy the class with something like this (that also adds an optional header used for authentication - in a poor adn non-generic way, right now - and allows you to specify a different service name for the "clones".</div><div><br></div><div><br></div><div><div><font face="courier new, monospace">def SpyneServiceFactory(serviceClass, with_headers=False, service_name=None):</font></div><div><font face="courier new, monospace">    """</font></div><div><font face="courier new, monospace">    Factory for spyne's ServiceBase classes, required by Spyne to be able to use the same service definition from</font></div><div><font face="courier new, monospace">    two or more different web services Applications at the same time.</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    :param dec[6] serviceClass:   a ServiceBase subclass implementing web service calls</font></div><div><font face="courier new, monospace">    :param str[2] with_headers:   if True, the class will expect a RequestHeader with </font></div><div><font face="courier new, monospace">                                  username and password in the header of every call (makes sense for SOAP only)</font></div><div><font face="courier new, monospace">    :returns:                     a deepcopy of the input serviceClass</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    """</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    import copy</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    ClonedServiceProvider = copy.deepcopy(serviceClass)</font></div><div><font face="courier new, monospace">    if with_headers:</font></div><div><font face="courier new, monospace">        ClonedServiceProvider.__in_header__ = RequestHeader</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    if service_name:</font></div><div><font face="courier new, monospace">        ClonedServiceProvider.__service_name__ = service_name</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    def _on_method_call(ctx):</font></div><div><font face="courier new, monospace">        if ctx.in_header is None:</font></div><div><font face="courier new, monospace">            <a href="http://log.info">log.info</a>("{0} - unauthenticated call".format(serviceClass.__name__))</font></div><div><font face="courier new, monospace">            return</font></div><div><font face="courier new, monospace">        <a href="http://log.info">log.info</a>("{0} - auth requested for {1}/{2}".format(serviceClass.__name__, ctx.in_header.username, ctx.in_header.password))</font></div><div><font face="courier new, monospace">        # authenticate the user and raise an authorization exception if this fails. Using a username/authtoken </font></div><div><font face="courier new, monospace">        # like in spyne's own example is recommened but not what the current service consumer wants to do...</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">    if with_headers:</font></div><div><font face="courier new, monospace">        ClonedServiceProvider.event_manager.add_listener('method_call', _on_method_call)</font></div><div><font face="courier new, monospace">    return ClonedServiceProvider</font></div></div><div><br></div><div><br></div><div><br></div><div>Is this something acceptable or did I miss some subtle (...or obvious!) side effect that will result in errors or worse once I start to use it "for real"?<br>A test implementation looks to be working correctly right now, but concurrent use isn't enough to expose possible "reentrancy" problems.<br><br><br></div><div>Thanks,</div><div>Roberto</div><div><br></div></div>