python thrift union type can not be serialized?

2.3k views Asked by At

I define a union type in topic.thrift file, and generate gen-py. like this:

union Generic{
1: string s,
2: bool b,
3: i64 i,
4: double d}

struct Article{
1: string title,
2: string content,
3: Generic test}

and the serialize code like this:

transport_out = TTransport.TMemoryBuffer()
protocol_out = TBinaryProtocol.TBinaryProtocol(transport_out)
parse_item.write(protocol_out)
bytes = transport_out.getvalue()

the parse_item is a object of Article:

parse_item = Article()
parse_item.test = 1

no matter str, int, bool, or double value assigned to parse_item.test, I all get a error like this:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "gen-py/topic/ttypes.py", line 189, in write
self.test.write(oprot)
AttributeError: 'str' object has no attribute 'write'

I really don't know why? Anyone have ideas?

1

There are 1 answers

1
codeSF On

This is a tricky one. The problem is that the Python implementation leverages Python's dynamic typing. By assigning an int to the parse_item struct "test" attribute, you change its type to "int" (!). Surprising, but upon reflection sensible.

To get the right types for serialization you need to create a Generic instance and set test to it.

Here's a walk through with working code:

root@154eadaaea91:/ThriftBook/test2# cat un.thrift 
union Generic{
1: string s,
2: bool b,
3: i64 i,
4: double d}

struct Article{
1: string title,
2: string content,
3: Generic test}

root@154eadaaea91:/ThriftBook/test2# thrift -gen py un.thrift 
root@154eadaaea91:/ThriftBook/test2# ll
total 20
drwxr-xr-x 3 root root 4096 Dec 22 20:07 ./
drwxr-xr-x 8 root root 4096 Dec 22 19:53 ../
drwxr-xr-x 3 root root 4096 Dec 22 20:07 gen-py/
-rw-r--r-- 1 root root  133 Dec 22 15:46 un.thrift
-rw-r--r-- 1 root root  589 Dec 22 20:07 untest.py
root@154eadaaea91:/ThriftBook/test2# cat untest.py 
import sys
sys.path.append("gen-py")

from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from un import ttypes

parse_item = ttypes.Article()
gen = ttypes.Generic()
gen.i = 1
parse_item.test = gen

transport_out = TTransport.TMemoryBuffer()
protocol_out = TBinaryProtocol.TBinaryProtocol(transport_out)
parse_item.write(protocol_out)
bytes = transport_out.getvalue()

transport_in = TTransport.TMemoryBuffer(bytes)
protocol_in = TBinaryProtocol.TBinaryProtocol(transport_in)
dump_item = ttypes.Article()
dump_item.read(protocol_in)
print(dump_item.test.i)
root@154eadaaea91:/ThriftBook/test2# python untest.py 
1
root@154eadaaea91:/ThriftBook/test2#