Edit
Example,
class A(ComplexModel):
Id = Unicode
class B(ComplexModel):
__extends__ = A
Name = Unicode
@rpc(String, _returns=A)
def hello(self, name):
ret = B()
B.Id = '123'
B.Name = name
return ret
How do you handle this behavior so it doesn't return an object of A
?
How would I write the spyne
decorators to correctly return more than one type? If, for example, _returns is set to ZObj
then returning an XAccount
(like in the code) doesn't do anything.
Can I write the XAccount
object so that it extends ZObj
and is a valid return type?
@rpc(String, _returns=(ZObj, XAccount))
def hello(self, name):
acc = XAccount(
user_name = name.upper(),
first_name = name,
last_name = 'last ' + name
)
return acc
Class examples....
class ZObj(ComplexModel):
id = Unicode(pattern='[a-zA-Z0-9]{32}|\d+')
class Account(DeclarativeBase):
__tablename__ = 'account'
id = Column(Integer, primary_key=True)
user_name = Column(String(256))
first_name = Column(String(256))
last_name = Column(String(256))
class XAccount(TableModel):
__table__ = Account.__table__
Deleting my previous answer as you apparently need polymorphism, not multiple return types.
So, There are two ways of doing polymorphism in Spyne: The Python way and the Spyne way.
Let:
class A(ComplexModel):
i = Integer
class B(A):
s = Unicode
class C(A):
d = DateTime
The Python way uses duck typing to return values.
Let's define a generic class:
class GenericA(ComplexModel):
i = Integer
s = Unicode
d = DateTime
and use it as return value of our sample service:
class SomeService(ServiceBase):
@rpc(Unicode(values=['A', 'B', 'C']), _returns=GenericA)
def get_some_a(self, type_name):
# (...)
This way, you get your data, but it's tagged as a GenericA
object. If you don't care about this, you can create a class that has all types from all objects (assuming attributes with same names have the same type) and just be done with it. This is easy, stable and works today.
If that's not enough for your needs, you have to do the polymorphism the Spyne way. To do that, first set your return type to the base class:
class SomeService(ServiceBase):
@rpc(Unicode(values=['A', 'B', 'C']), _returns=A)
def get_some_a(self, type_name):
# (...)
and tag your output protocol to be polymorphic:
application = Application([SomeService], 'tns',
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11(polymorphic=True)
)
This requires at least Spyne-2.12.
Working example: https://github.com/arskom/spyne/blob/a1b3593f3754a9c8a6787c29ff50f591db89fd49/examples/xml/polymorphism.py
Also, you don't need to do this:
class Account(DeclarativeBase):
__tablename__ = 'account'
id = Column(Integer, primary_key=True)
user_name = Column(String(256))
first_name = Column(String(256))
last_name = Column(String(256))
class XAccount(TableModel):
__table__ = Account.__table__
This works just as well:
from spyne import TTableModel
TableModel = TTableModel() # Think of this as Spyne's declarative_base
class Account(TableModel):
__tablename__ = 'account'
id = Integer(primary_key=True)
user_name = Unicode(256)
first_name = Unicode(256)
last_name = Unicode(256)
where your table metadata is in TableModel.Attributes.sqla_metadata
Objects created this way are usable in both in SQLAlchemy queries and as Spyne types.