Python code generated by Thrift up to version 0.10.0 does not support recursive structures. The issue was first reported in July 2014. In python, types are discovered dynamically so a recursive reference to a class inside of its definition does not work.
For example, the class definition below
causes the error,
For python, Thrift generates code that exhibits this problem because it allows recursive definitions in .thrift files.
The above thrift code generates the following python code,
The thrift core python code uses these thrift_spec
tuples, which contain type information and default values, for serialization and for default arguments to constructors. It is then important to preserve these tuples when supporting recursive structures, but we can see that they cannot exist as written.
There are two pretty apparent problems though:
thrift_spec
is to use Recursive
then it needs to be defined and monkey-patched onto the class after the class is defined. There is no other way to make this recursive definition work in python.thrift_spec
refers to itself via Recursive.thrift_spec
. In python a tuple is a value type. Any attempt to make a value type self-referential will just result in a copy of that tuple rather than a true self-reference. Basically, self-referential tuples don’t really make sense in python.Facebook’s fbthrift
contains a solution to this problem which I followed for the solution in the thrift
project. There are 3 major changes,
thrift_spec
definitions to the end of the ttypes file. Or, in the case of a service definition, after the service.thrift_spec
for a TStruct
object to [<Struct>, None]
, (to a list which is a reference type)fix_spec
to wire up the recursive references to thrift_spec
so that they contain [<Struct>, <Struct>.thrift_spec]
With these changes, Thrift now generates code that for the Recursive case above looks like this:
And the fix_spec
method recursively walks over the thrift_spec
definition and re-wires the references:
A bit ugly, but it should get the job done. There is a pull request for this change up at github.