2

I'm trying to inherit a decorated class like this

class SOAPCategoy(ComplexModel):
    id = Integer
    CategoyName = Unicode

class SOAPServiceBase(ServiceBase):
   @rpc(Integer, _returns=SOAPSeller)
   def Item(self, pId):
      ....
      return SOAPCategory()

class SOAPCategoryService(SOAPServiceBase):
   pass

.
.
.
wsgi_app = wsgi_soap_application([SOAPCategoryService], 'test.soap')

Then it throws an error:

File "...spyne/interface/xml_schema/_base.py", line 186, in build_validation_schema
f = open('%s/%s.xsd' % (tmp_dir_name, pref_tns), 'r')
IOError: [Errno 2] No such file or directory: '/tmp/spyne9y_uw9/tns.xsd'

Part of _base.py source code

def build_validation_schema(self):
    """Build application schema specifically for xml validation purposes."""

    self.build_schema_nodes(with_schema_location=True)

    pref_tns = self.interface.get_namespace_prefix(self.interface.tns)
    tmp_dir_name = tempfile.mkdtemp(prefix='spyne')
    logger.debug("generating schema for targetNamespace=%r, prefix: "
              "%r in dir %r" % (self.interface.tns, pref_tns, tmp_dir_name))

    # serialize nodes to files
    for k, v in self.schema_dict.items():
        file_name = '%s/%s.xsd' % (tmp_dir_name, k)
        f = open(file_name, 'wb')
        etree.ElementTree(v).write(f, pretty_print=True)
        f.close()
        logger.debug("writing %r for ns %s" % (file_name,
                                                   self.interface.nsmap[k]))

    f = open('%s/%s.xsd' % (tmp_dir_name, pref_tns), 'r')
Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
ivocnii
  • 31
  • 2

2 Answers2

1

Spyne is designed to prevent you from using inheritance with ServiceBase children. You must use composition.

class SOAPServiceBase(ServiceBase):
   @rpc(Integer, _returns=SOAPSeller)
   def Item(self, pId):
      # ....
      return SOAPCategory()

class SOAPCategoryService(ServiceBase):
   # ...

wsgi_app = wsgi_soap_application([SOAPServiceBase, SOAPCategoryService], 'test.soap')

If you need to export the same service pack from different endpoints, you should do this:

def TSoapServiceBase():
    class SOAPServiceBase(ServiceBase):
       @rpc(Integer, _returns=SOAPSeller)
       def Item(self, pId):
          # ....
          return SOAPCategory()

    return SOAPServiceBase

some_app = wsgi_soap_application([TSoapServiceBase()], 'test.soap')
some_other_app = wsgi_soap_application([TSoapServiceBase()], 'test.soap')
# etc...
Burak Arslan
  • 7,671
  • 2
  • 15
  • 24
1

If you want to replace some service method you could extend a service and next copy methods from parent service class:

# Define main service class.
class OldService(ServiceBase):
    @srpc(Unicode, _returns=Unicode)
    def some_method(input):
        return u'Original!'

# Overload service class.
class NewService(OldService):
    @srpc(Unicode, Unicode, Unicode, _returns=Unicode)
    def some_method(input1, input2, input3):
        return u'Replaced!'

# Attach old methods.
for base in NewService.__bases__:
    if issubclass(base, ServiceBase):
        for name, method in base.public_methods.iteritems():
            if name not in NewService.public_methods:
                NewService.public_methods[name] = method

Tested with Spyne 2.11.0. And... it is not a good solution.

Pavel Patrin
  • 1,630
  • 1
  • 19
  • 33