blob: 85eb3f67a478deba75bc006b2e8b3af396a34807 [file] [log] [blame]
Mark Sleee9ce01c2007-05-16 02:29:53 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
David Reiss0d6eb962008-03-27 21:41:45 +00007#include <string>
8#include <fstream>
9#include <iostream>
10#include <vector>
11
Mark Sleee50b3092006-09-04 00:06:47 +000012#include <stdlib.h>
13#include <sys/stat.h>
Mark Slee748e5762006-10-04 21:51:05 +000014#include <sys/types.h>
Mark Sleee50b3092006-09-04 00:06:47 +000015#include <sstream>
David Reiss382fc302007-08-25 18:01:30 +000016#include <algorithm>
David Reiss0d6eb962008-03-27 21:41:45 +000017#include "t_generator.h"
David Reiss204420f2008-01-11 20:59:03 +000018#include "platform.h"
Mark Sleee50b3092006-09-04 00:06:47 +000019using namespace std;
20
David Reiss0d6eb962008-03-27 21:41:45 +000021
22/**
23 * Python code generator.
24 *
25 * @author Mark Slee <mcslee@facebook.com>
26 */
27class t_py_generator : public t_generator {
28 public:
29 t_py_generator(
30 t_program* program,
31 const std::map<std::string, std::string>& parsed_options,
32 const std::string& option_string)
33 : t_generator(program)
34 {
35 std::map<std::string, std::string>::const_iterator iter;
36
37 iter = parsed_options.find("new_style");
38 gen_newstyle_ = (iter != parsed_options.end());
39
40 out_dir_base_ = "gen-py";
41 }
42
43 /**
44 * Init and close methods
45 */
46
47 void init_generator();
48 void close_generator();
49
50 /**
51 * Program-level generation functions
52 */
53
54 void generate_typedef (t_typedef* ttypedef);
55 void generate_enum (t_enum* tenum);
56 void generate_const (t_const* tconst);
57 void generate_struct (t_struct* tstruct);
58 void generate_xception (t_struct* txception);
59 void generate_service (t_service* tservice);
60
61 std::string render_const_value(t_type* type, t_const_value* value);
62
63 /**
64 * Struct generation code
65 */
66
67 void generate_py_struct(t_struct* tstruct, bool is_exception);
68 void generate_py_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
69 void generate_py_struct_reader(std::ofstream& out, t_struct* tstruct);
70 void generate_py_struct_writer(std::ofstream& out, t_struct* tstruct);
71 void generate_py_function_helpers(t_function* tfunction);
72
73 /**
74 * Service-level generation functions
75 */
76
77 void generate_service_helpers (t_service* tservice);
78 void generate_service_interface (t_service* tservice);
79 void generate_service_client (t_service* tservice);
80 void generate_service_remote (t_service* tservice);
81 void generate_service_server (t_service* tservice);
82 void generate_process_function (t_service* tservice, t_function* tfunction);
83
84 /**
85 * Serialization constructs
86 */
87
88 void generate_deserialize_field (std::ofstream &out,
89 t_field* tfield,
90 std::string prefix="",
91 bool inclass=false);
92
93 void generate_deserialize_struct (std::ofstream &out,
94 t_struct* tstruct,
95 std::string prefix="");
96
97 void generate_deserialize_container (std::ofstream &out,
98 t_type* ttype,
99 std::string prefix="");
100
101 void generate_deserialize_set_element (std::ofstream &out,
102 t_set* tset,
103 std::string prefix="");
104
105 void generate_deserialize_map_element (std::ofstream &out,
106 t_map* tmap,
107 std::string prefix="");
108
109 void generate_deserialize_list_element (std::ofstream &out,
110 t_list* tlist,
111 std::string prefix="");
112
113 void generate_serialize_field (std::ofstream &out,
114 t_field* tfield,
115 std::string prefix="");
116
117 void generate_serialize_struct (std::ofstream &out,
118 t_struct* tstruct,
119 std::string prefix="");
120
121 void generate_serialize_container (std::ofstream &out,
122 t_type* ttype,
123 std::string prefix="");
124
125 void generate_serialize_map_element (std::ofstream &out,
126 t_map* tmap,
127 std::string kiter,
128 std::string viter);
129
130 void generate_serialize_set_element (std::ofstream &out,
131 t_set* tmap,
132 std::string iter);
133
134 void generate_serialize_list_element (std::ofstream &out,
135 t_list* tlist,
136 std::string iter);
137
138 /**
139 * Helper rendering functions
140 */
141
142 std::string py_autogen_comment();
143 std::string py_imports();
144 std::string render_includes();
145 std::string render_fastbinary_includes();
146 std::string declare_field(t_field* tfield);
147 std::string type_name(t_type* ttype);
148 std::string function_signature(t_function* tfunction, std::string prefix="");
149 std::string argument_list(t_struct* tstruct);
150 std::string type_to_enum(t_type* ttype);
151 std::string type_to_spec_args(t_type* ttype);
152
153 static std::string get_real_py_module(const t_program* program) {
David Reiss320e45c2008-03-27 21:41:54 +0000154 std::string real_module = program->get_namespace("py");
David Reiss0d6eb962008-03-27 21:41:45 +0000155 if (real_module.empty()) {
156 return program->get_name();
157 }
158 return real_module;
159 }
160
161 private:
162
163 /**
164 * True iff we should generate new-style classes.
165 */
166 bool gen_newstyle_;
167
168 /**
169 * File streams
170 */
171
172 std::ofstream f_types_;
173 std::ofstream f_consts_;
174 std::ofstream f_service_;
175
176 std::string package_dir_;
177
178};
179
180
Mark Sleee50b3092006-09-04 00:06:47 +0000181/**
182 * Prepares for file generation by opening up the necessary file output
183 * streams.
184 *
185 * @param tprogram The program to generate
186 */
Mark Sleef0712dc2006-10-25 19:03:57 +0000187void t_py_generator::init_generator() {
Mark Sleee50b3092006-09-04 00:06:47 +0000188 // Make output directory
David Reissc6fc3292007-08-30 00:58:43 +0000189 string module = get_real_py_module(program_);
dweatherford65b70752007-10-31 02:18:14 +0000190 package_dir_ = get_out_dir();
David Reissc6fc3292007-08-30 00:58:43 +0000191 while (true) {
192 // TODO: Do better error checking here.
David Reiss204420f2008-01-11 20:59:03 +0000193 MKDIR(package_dir_.c_str());
David Reissc6fc3292007-08-30 00:58:43 +0000194 std::ofstream init_py((package_dir_+"/__init__.py").c_str());
195 init_py.close();
196 if (module.empty()) {
197 break;
198 }
199 string::size_type pos = module.find('.');
200 if (pos == string::npos) {
201 package_dir_ += "/";
202 package_dir_ += module;
203 module.clear();
204 } else {
205 package_dir_ += "/";
206 package_dir_ += module.substr(0, pos);
207 module.erase(0, pos+1);
208 }
209 }
Mark Sleee50b3092006-09-04 00:06:47 +0000210
211 // Make output file
Mark Sleeecf490e2007-02-21 00:05:18 +0000212 string f_types_name = package_dir_+"/"+"ttypes.py";
Mark Sleee50b3092006-09-04 00:06:47 +0000213 f_types_.open(f_types_name.c_str());
214
Mark Sleeecf490e2007-02-21 00:05:18 +0000215 string f_consts_name = package_dir_+"/"+"constants.py";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000216 f_consts_.open(f_consts_name.c_str());
217
Mark Sleeecf490e2007-02-21 00:05:18 +0000218 string f_init_name = package_dir_+"/__init__.py";
219 ofstream f_init;
220 f_init.open(f_init_name.c_str());
221 f_init <<
222 "__all__ = ['ttypes', 'constants'";
223 vector<t_service*> services = program_->get_services();
224 vector<t_service*>::iterator sv_iter;
225 for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
226 f_init << ", '" << (*sv_iter)->get_name() << "'";
227 }
228 f_init << "]" << endl;
229 f_init.close();
230
Mark Sleee50b3092006-09-04 00:06:47 +0000231 // Print header
232 f_types_ <<
233 py_autogen_comment() << endl <<
234 py_imports() << endl <<
David Reiss382fc302007-08-25 18:01:30 +0000235 render_includes() << endl <<
David Reiss5db3e922007-08-30 23:07:45 +0000236 render_fastbinary_includes() <<
237 endl << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000238
239 f_consts_ <<
240 py_autogen_comment() << endl <<
241 py_imports() << endl <<
Mark Sleeecf490e2007-02-21 00:05:18 +0000242 "from ttypes import *" << endl <<
Mark Sleeaa7671d2006-11-29 03:19:31 +0000243 endl;
Mark Sleef0712dc2006-10-25 19:03:57 +0000244}
245
246/**
247 * Renders all the imports necessary for including another Thrift program
248 */
249string t_py_generator::render_includes() {
250 const vector<t_program*>& includes = program_->get_includes();
251 string result = "";
252 for (size_t i = 0; i < includes.size(); ++i) {
David Reissc6fc3292007-08-30 00:58:43 +0000253 result += "import " + get_real_py_module(includes[i]) + ".ttypes\n";
Mark Sleef0712dc2006-10-25 19:03:57 +0000254 }
255 if (includes.size() > 0) {
256 result += "\n";
257 }
258 return result;
Mark Sleee50b3092006-09-04 00:06:47 +0000259}
260
261/**
David Reiss5db3e922007-08-30 23:07:45 +0000262 * Renders all the imports necessary to use the accelerated TBinaryProtocol
263 */
264string t_py_generator::render_fastbinary_includes() {
265 return
266 "from thrift.transport import TTransport\n"
267 "from thrift.protocol import TBinaryProtocol\n"
268 "try:\n"
269 " from thrift.protocol import fastbinary\n"
270 "except:\n"
271 " fastbinary = None\n";
272}
273
274/**
Mark Sleee50b3092006-09-04 00:06:47 +0000275 * Autogen'd comment
276 */
277string t_py_generator::py_autogen_comment() {
278 return
279 std::string("#\n") +
280 "# Autogenerated by Thrift\n" +
Mark Sleee50b3092006-09-04 00:06:47 +0000281 "#\n" +
282 "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
283 "#\n";
284}
285
286/**
Mark Sleef5377b32006-10-10 01:42:59 +0000287 * Prints standard thrift imports
Mark Sleee50b3092006-09-04 00:06:47 +0000288 */
289string t_py_generator::py_imports() {
290 return
Mark Sleeb0060b02007-02-21 05:37:50 +0000291 string("from thrift.Thrift import *");
Mark Sleee50b3092006-09-04 00:06:47 +0000292}
293
294/**
Mark Sleef5377b32006-10-10 01:42:59 +0000295 * Closes the type files
Mark Sleee50b3092006-09-04 00:06:47 +0000296 */
Mark Sleef0712dc2006-10-25 19:03:57 +0000297void t_py_generator::close_generator() {
Mark Sleee50b3092006-09-04 00:06:47 +0000298 // Close types file
299 f_types_.close();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000300 f_consts_.close();
Mark Sleee50b3092006-09-04 00:06:47 +0000301}
302
303/**
304 * Generates a typedef. This is not done in Python, types are all implicit.
305 *
306 * @param ttypedef The type definition
307 */
308void t_py_generator::generate_typedef(t_typedef* ttypedef) {}
309
310/**
Mark Sleef5377b32006-10-10 01:42:59 +0000311 * Generates code for an enumerated type. Done using a class to scope
312 * the values.
Mark Sleee50b3092006-09-04 00:06:47 +0000313 *
314 * @param tenum The enumeration
315 */
316void t_py_generator::generate_enum(t_enum* tenum) {
317 f_types_ <<
David Reiss6495adb2007-12-18 03:37:30 +0000318 "class " << tenum->get_name() <<
319 (gen_newstyle_ ? "(object)" : "") <<
320 ":" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000321 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000322
Mark Slee30152872006-11-28 01:24:07 +0000323 vector<t_enum_value*> constants = tenum->get_constants();
324 vector<t_enum_value*>::iterator c_iter;
Mark Sleee50b3092006-09-04 00:06:47 +0000325 int value = -1;
326 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
327 if ((*c_iter)->has_value()) {
328 value = (*c_iter)->get_value();
329 } else {
330 ++value;
331 }
332
333 f_types_ <<
334 indent() << (*c_iter)->get_name() << " = " << value << endl;
335 }
336
337 indent_down();
338 f_types_ << endl;
339}
340
Mark Sleef5377b32006-10-10 01:42:59 +0000341/**
Mark Sleeaa7671d2006-11-29 03:19:31 +0000342 * Generate a constant value
343 */
344void t_py_generator::generate_const(t_const* tconst) {
345 t_type* type = tconst->get_type();
346 string name = tconst->get_name();
347 t_const_value* value = tconst->get_value();
David Reiss382fc302007-08-25 18:01:30 +0000348
Mark Slee7ff32452007-02-01 05:26:18 +0000349 indent(f_consts_) << name << " = " << render_const_value(type, value);
Mark Sleeaa7671d2006-11-29 03:19:31 +0000350 f_consts_ << endl << endl;
351}
352
353/**
354 * Prints the value of a constant with the given type. Note that type checking
355 * is NOT performed in this function as it is always run beforehand using the
356 * validate_types method in main.cc
357 */
Mark Slee7ff32452007-02-01 05:26:18 +0000358string t_py_generator::render_const_value(t_type* type, t_const_value* value) {
David Reiss9a4edfa2008-05-01 05:52:50 +0000359 type = get_true_type(type);
Mark Slee7ff32452007-02-01 05:26:18 +0000360 std::ostringstream out;
361
Mark Sleeaa7671d2006-11-29 03:19:31 +0000362 if (type->is_base_type()) {
363 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
364 switch (tbase) {
365 case t_base_type::TYPE_STRING:
Mark Slee7ff32452007-02-01 05:26:18 +0000366 out << "'" << value->get_string() << "'";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000367 break;
368 case t_base_type::TYPE_BOOL:
Mark Slee7ff32452007-02-01 05:26:18 +0000369 out << (value->get_integer() > 0 ? "True" : "False");
Mark Sleeaa7671d2006-11-29 03:19:31 +0000370 break;
371 case t_base_type::TYPE_BYTE:
372 case t_base_type::TYPE_I16:
373 case t_base_type::TYPE_I32:
374 case t_base_type::TYPE_I64:
Mark Slee7ff32452007-02-01 05:26:18 +0000375 out << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000376 break;
377 case t_base_type::TYPE_DOUBLE:
378 if (value->get_type() == t_const_value::CV_INTEGER) {
Mark Slee7ff32452007-02-01 05:26:18 +0000379 out << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000380 } else {
Mark Slee7ff32452007-02-01 05:26:18 +0000381 out << value->get_double();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000382 }
383 break;
384 default:
David Reissdd7796f2007-08-28 21:09:06 +0000385 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
Mark Sleeaa7671d2006-11-29 03:19:31 +0000386 }
387 } else if (type->is_enum()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000388 indent(out) << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000389 } else if (type->is_struct() || type->is_xception()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000390 out << type->get_name() << "({" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000391 indent_up();
392 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
393 vector<t_field*>::const_iterator f_iter;
394 const map<t_const_value*, t_const_value*>& val = value->get_map();
395 map<t_const_value*, t_const_value*>::const_iterator v_iter;
396 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
397 t_type* field_type = NULL;
398 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
399 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
400 field_type = (*f_iter)->get_type();
401 }
402 }
403 if (field_type == NULL) {
404 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
405 }
Mark Slee7ff32452007-02-01 05:26:18 +0000406 out << indent();
407 out << render_const_value(g_type_string, v_iter->first);
408 out << " : ";
409 out << render_const_value(field_type, v_iter->second);
410 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000411 }
412 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000413 indent(out) << "})";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000414 } else if (type->is_map()) {
415 t_type* ktype = ((t_map*)type)->get_key_type();
416 t_type* vtype = ((t_map*)type)->get_val_type();
Mark Slee7ff32452007-02-01 05:26:18 +0000417 out << "{" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000418 indent_up();
419 const map<t_const_value*, t_const_value*>& val = value->get_map();
420 map<t_const_value*, t_const_value*>::const_iterator v_iter;
421 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000422 out << indent();
423 out << render_const_value(ktype, v_iter->first);
424 out << " : ";
425 out << render_const_value(vtype, v_iter->second);
426 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000427 }
428 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000429 indent(out) << "}";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000430 } else if (type->is_list() || type->is_set()) {
431 t_type* etype;
432 if (type->is_list()) {
433 etype = ((t_list*)type)->get_elem_type();
434 } else {
435 etype = ((t_set*)type)->get_elem_type();
436 }
Mark Slee600cdb32006-11-29 22:06:42 +0000437 if (type->is_set()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000438 out << "set(";
Mark Slee600cdb32006-11-29 22:06:42 +0000439 }
Mark Slee7ff32452007-02-01 05:26:18 +0000440 out << "[" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000441 indent_up();
442 const vector<t_const_value*>& val = value->get_list();
443 vector<t_const_value*>::const_iterator v_iter;
444 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000445 out << indent();
446 out << render_const_value(etype, *v_iter);
447 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000448 }
449 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000450 indent(out) << "]";
Mark Slee600cdb32006-11-29 22:06:42 +0000451 if (type->is_set()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000452 out << ")";
Mark Slee600cdb32006-11-29 22:06:42 +0000453 }
David Reiss9a4edfa2008-05-01 05:52:50 +0000454 } else {
455 throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000456 }
Mark Slee7ff32452007-02-01 05:26:18 +0000457
458 return out.str();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000459}
460
461/**
Mark Sleef5377b32006-10-10 01:42:59 +0000462 * Generates a python struct
463 */
Mark Sleee50b3092006-09-04 00:06:47 +0000464void t_py_generator::generate_struct(t_struct* tstruct) {
465 generate_py_struct(tstruct, false);
466}
467
468/**
469 * Generates a struct definition for a thrift exception. Basically the same
470 * as a struct but extends the Exception class.
471 *
472 * @param txception The struct definition
473 */
474void t_py_generator::generate_xception(t_struct* txception) {
David Reiss382fc302007-08-25 18:01:30 +0000475 generate_py_struct(txception, true);
Mark Sleee50b3092006-09-04 00:06:47 +0000476}
477
Mark Sleef5377b32006-10-10 01:42:59 +0000478/**
479 * Generates a python struct
480 */
Mark Sleee50b3092006-09-04 00:06:47 +0000481void t_py_generator::generate_py_struct(t_struct* tstruct,
482 bool is_exception) {
483 generate_py_struct_definition(f_types_, tstruct, is_exception);
484}
485
486/**
David Reiss382fc302007-08-25 18:01:30 +0000487 * Comparator to sort fields in ascending order by key.
488 * Make this a functor instead of a function to help GCC inline it.
489 * The arguments are (const) references to const pointers to const t_fields.
490 * Unfortunately, we cannot declare it within the function. Boo!
491 * http://www.open-std.org/jtc1/sc22/open/n2356/ (paragraph 9).
492 */
493struct FieldKeyCompare {
494 bool operator()(t_field const * const & a, t_field const * const & b) {
495 return a->get_key() < b->get_key();
496 }
497};
498
499/**
David Reiss6495adb2007-12-18 03:37:30 +0000500 * Generates a struct definition for a thrift data type.
Mark Sleee50b3092006-09-04 00:06:47 +0000501 *
502 * @param tstruct The struct definition
503 */
504void t_py_generator::generate_py_struct_definition(ofstream& out,
505 t_struct* tstruct,
506 bool is_exception,
507 bool is_result) {
David Reiss382fc302007-08-25 18:01:30 +0000508
Mark Sleee50b3092006-09-04 00:06:47 +0000509 const vector<t_field*>& members = tstruct->get_members();
David Reiss382fc302007-08-25 18:01:30 +0000510 vector<t_field*>::const_iterator m_iter;
511 vector<t_field*> sorted_members(members);
512 std::sort(sorted_members.begin(), sorted_members.end(), FieldKeyCompare());
Mark Sleee50b3092006-09-04 00:06:47 +0000513
514 out <<
515 "class " << tstruct->get_name();
516 if (is_exception) {
517 out << "(Exception)";
David Reiss6495adb2007-12-18 03:37:30 +0000518 } else if (gen_newstyle_) {
519 out << "(object)";
Mark Sleee50b3092006-09-04 00:06:47 +0000520 }
521 out <<
522 ":" << endl;
523 indent_up();
524
525 out << endl;
526
David Reiss382fc302007-08-25 18:01:30 +0000527 /*
528 Here we generate the structure specification for the fastbinary codec.
529 These specifications have the following structure:
530 thrift_spec -> tuple of item_spec
531 item_spec -> None | (tag, type_enum, name, spec_args, default)
532 tag -> integer
533 type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
534 name -> string_literal
535 default -> None # Handled by __init__
536 spec_args -> None # For simple types
537 | (type_enum, spec_args) # Value type for list/set
538 | (type_enum, spec_args, type_enum, spec_args)
539 # Key and value for map
540 | (class_name, spec_args_ptr) # For struct/exception
541 class_name -> identifier # Basically a pointer to the class
542 spec_args_ptr -> expression # just class_name.spec_args
543
544 TODO(dreiss): Consider making this work for structs with negative tags.
545 */
546
David Reiss5db3e922007-08-30 23:07:45 +0000547 // TODO(dreiss): Look into generating an empty tuple instead of None
548 // for structures with no members.
549 // TODO(dreiss): Test encoding of structs where some inner structs
550 // don't have thrift_spec.
David Reiss382fc302007-08-25 18:01:30 +0000551 if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
552 indent(out) << "thrift_spec = (" << endl;
553 indent_up();
554
555 int sorted_keys_pos = 0;
556 for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
557
558 for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
559 indent(out) << "None, # " << sorted_keys_pos << endl;
560 }
561
562 indent(out) << "(" << (*m_iter)->get_key() << ", "
563 << type_to_enum((*m_iter)->get_type()) << ", "
564 << "'" << (*m_iter)->get_name() << "'" << ", "
565 << type_to_spec_args((*m_iter)->get_type()) << ", "
566 << "None" << ", "
567 << "),"
568 << " # " << sorted_keys_pos
569 << endl;
570
571 sorted_keys_pos ++;
572 }
573
574 indent_down();
575 indent(out) << ")" << endl << endl;
David Reiss5db3e922007-08-30 23:07:45 +0000576 } else {
577 indent(out) << "thrift_spec = None" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000578 }
579
David Reiss5db3e922007-08-30 23:07:45 +0000580
Mark Sleee50b3092006-09-04 00:06:47 +0000581 out <<
Mark Sleeaa7671d2006-11-29 03:19:31 +0000582 indent() << "def __init__(self, d=None):" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000583 indent_up();
584
585 if (members.size() == 0) {
586 indent(out) <<
587 "pass" <<endl;
588 } else {
589 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000590 // This fills in default values, as opposed to nulls
591 indent(out) <<
592 declare_field(*m_iter) << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000593 }
Mark Sleeaa7671d2006-11-29 03:19:31 +0000594
595 indent(out) <<
596 "if isinstance(d, dict):" << endl;
597 indent_up();
598 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
599 out <<
600 indent() << "if '" << (*m_iter)->get_name() << "' in d:" << endl <<
601 indent() << " self." << (*m_iter)->get_name() << " = d['" << (*m_iter)->get_name() << "']" << endl;
602 }
603 indent_down();
Mark Sleee50b3092006-09-04 00:06:47 +0000604 }
605
606 indent_down();
David Reiss382fc302007-08-25 18:01:30 +0000607
Mark Sleee50b3092006-09-04 00:06:47 +0000608 out << endl;
609
David Reiss382fc302007-08-25 18:01:30 +0000610
Mark Sleee50b3092006-09-04 00:06:47 +0000611 generate_py_struct_reader(out, tstruct);
Mark Sleef5377b32006-10-10 01:42:59 +0000612 generate_py_struct_writer(out, tstruct);
Mark Sleee50b3092006-09-04 00:06:47 +0000613
Mark Sleef5377b32006-10-10 01:42:59 +0000614 // Printing utilities so that on the command line thrift
615 // structs look pretty like dictionaries
Mark Slee748e5762006-10-04 21:51:05 +0000616 out <<
David Reiss4d1c7122008-06-11 01:18:03 +0000617 indent() << "def __str__(self):" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +0000618 indent() << " return str(self.__dict__)" << endl <<
619 endl <<
David Reiss4d1c7122008-06-11 01:18:03 +0000620 indent() << "def __repr__(self):" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +0000621 indent() << " return repr(self.__dict__)" << endl <<
622 endl;
623
David Reiss382fc302007-08-25 18:01:30 +0000624 // Equality and inequality methods that compare by value
625 out <<
626 indent() << "def __eq__(self, other):" << endl;
627 indent_up();
628 out <<
629 indent() << "return isinstance(other, self.__class__) and "
630 "self.__dict__ == other.__dict__" << endl;
631 indent_down();
632 out << endl;
633
634 out <<
635 indent() << "def __ne__(self, other):" << endl;
636 indent_up();
637 out <<
638 indent() << "return not (self == other)" << endl;
639 indent_down();
640 out << endl;
641
Mark Sleee50b3092006-09-04 00:06:47 +0000642 indent_down();
643}
644
Mark Sleef5377b32006-10-10 01:42:59 +0000645/**
646 * Generates the read method for a struct
647 */
Mark Sleee50b3092006-09-04 00:06:47 +0000648void t_py_generator::generate_py_struct_reader(ofstream& out,
649 t_struct* tstruct) {
650 const vector<t_field*>& fields = tstruct->get_members();
651 vector<t_field*>::const_iterator f_iter;
652
653 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000654 "def read(self, iprot):" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000655 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000656
Mark Sleee50b3092006-09-04 00:06:47 +0000657 indent(out) <<
David Reiss382fc302007-08-25 18:01:30 +0000658 "if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
David Reiss5db3e922007-08-30 23:07:45 +0000659 "and isinstance(iprot.trans, TTransport.CReadableTransport) "
660 "and self.thrift_spec is not None "
661 "and fastbinary is not None:" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000662 indent_up();
663
664 indent(out) <<
665 "fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))" << endl;
666 indent(out) <<
667 "return" << endl;
668 indent_down();
669
670 indent(out) <<
671 "iprot.readStructBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000672
673 // Loop over reading in fields
674 indent(out) <<
675 "while True:" << endl;
676 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000677
Mark Sleee50b3092006-09-04 00:06:47 +0000678 // Read beginning field marker
679 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000680 "(fname, ftype, fid) = iprot.readFieldBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000681
682 // Check for field STOP marker and break
683 indent(out) <<
684 "if ftype == TType.STOP:" << endl;
685 indent_up();
686 indent(out) <<
687 "break" << endl;
688 indent_down();
David Reiss382fc302007-08-25 18:01:30 +0000689
Mark Sleee50b3092006-09-04 00:06:47 +0000690 // Switch statement on the field we are reading
691 bool first = true;
David Reiss382fc302007-08-25 18:01:30 +0000692
Mark Sleee50b3092006-09-04 00:06:47 +0000693 // Generate deserialization code for known cases
694 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
695 if (first) {
696 first = false;
697 out <<
698 indent() << "if ";
699 } else {
700 out <<
701 indent() << "elif ";
702 }
703 out << "fid == " << (*f_iter)->get_key() << ":" << endl;
704 indent_up();
Mark Slee2006d992007-01-29 17:58:54 +0000705 indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl;
706 indent_up();
Mark Sleee50b3092006-09-04 00:06:47 +0000707 generate_deserialize_field(out, *f_iter, "self.");
708 indent_down();
Mark Slee2006d992007-01-29 17:58:54 +0000709 out <<
710 indent() << "else:" << endl <<
711 indent() << " iprot.skip(ftype)" << endl;
712 indent_down();
Mark Sleee50b3092006-09-04 00:06:47 +0000713 }
David Reiss382fc302007-08-25 18:01:30 +0000714
Mark Sleee50b3092006-09-04 00:06:47 +0000715 // In the default case we skip the field
716 out <<
717 indent() << "else:" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +0000718 indent() << " iprot.skip(ftype)" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000719
Mark Sleee50b3092006-09-04 00:06:47 +0000720 // Read field end marker
721 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000722 "iprot.readFieldEnd()" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000723
Mark Sleee50b3092006-09-04 00:06:47 +0000724 indent_down();
David Reiss382fc302007-08-25 18:01:30 +0000725
Mark Sleee50b3092006-09-04 00:06:47 +0000726 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000727 "iprot.readStructEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000728
729 indent_down();
730 out << endl;
731}
732
733void t_py_generator::generate_py_struct_writer(ofstream& out,
734 t_struct* tstruct) {
735 string name = tstruct->get_name();
736 const vector<t_field*>& fields = tstruct->get_members();
737 vector<t_field*>::const_iterator f_iter;
738
739 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000740 "def write(self, oprot):" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000741 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000742
743 indent(out) <<
David Reiss5db3e922007-08-30 23:07:45 +0000744 "if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
745 "and self.thrift_spec is not None "
746 "and fastbinary is not None:" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000747 indent_up();
748
749 indent(out) <<
750 "oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))" << endl;
751 indent(out) <<
752 "return" << endl;
753 indent_down();
754
Mark Sleee50b3092006-09-04 00:06:47 +0000755 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000756 "oprot.writeStructBegin('" << name << "')" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000757
758 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
759 // Write field header
760 indent(out) <<
Mark Sleee50b3092006-09-04 00:06:47 +0000761 "if self." << (*f_iter)->get_name() << " != None:" << endl;
762 indent_up();
763 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000764 "oprot.writeFieldBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +0000765 "'" << (*f_iter)->get_name() << "', " <<
766 type_to_enum((*f_iter)->get_type()) << ", " <<
767 (*f_iter)->get_key() << ")" << endl;
768
769 // Write field contents
770 generate_serialize_field(out, *f_iter, "self.");
771
772 // Write field closer
773 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000774 "oprot.writeFieldEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000775
776 indent_down();
777 }
778
779 // Write the struct map
780 out <<
Mark Slee5946a182006-10-25 21:38:39 +0000781 indent() << "oprot.writeFieldStop()" << endl <<
782 indent() << "oprot.writeStructEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000783
784 indent_down();
785 out <<
786 endl;
787}
788
789/**
790 * Generates a thrift service.
791 *
792 * @param tservice The service definition
793 */
794void t_py_generator::generate_service(t_service* tservice) {
Mark Sleeecf490e2007-02-21 00:05:18 +0000795 string f_service_name = package_dir_+"/"+service_name_+".py";
Mark Sleee50b3092006-09-04 00:06:47 +0000796 f_service_.open(f_service_name.c_str());
797
798 f_service_ <<
799 py_autogen_comment() << endl <<
800 py_imports() << endl;
801
Mark Sleef0712dc2006-10-25 19:03:57 +0000802 if (tservice->get_extends() != NULL) {
803 f_service_ <<
David Reissc6fc3292007-08-30 00:58:43 +0000804 "import " << get_real_py_module(tservice->get_extends()->get_program()) <<
805 "." << tservice->get_extends()->get_name() << endl;
Mark Sleef0712dc2006-10-25 19:03:57 +0000806 }
807
Mark Sleee50b3092006-09-04 00:06:47 +0000808 f_service_ <<
David Reiss382fc302007-08-25 18:01:30 +0000809 "from ttypes import *" << endl <<
Mark Sleec9676562006-09-05 17:34:52 +0000810 "from thrift.Thrift import TProcessor" << endl <<
David Reiss5db3e922007-08-30 23:07:45 +0000811 render_fastbinary_includes() <<
812 endl << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000813
814 // Generate the three main parts of the service (well, two for now in PHP)
815 generate_service_interface(tservice);
816 generate_service_client(tservice);
Mark Sleec9676562006-09-05 17:34:52 +0000817 generate_service_server(tservice);
Mark Sleef0712dc2006-10-25 19:03:57 +0000818 generate_service_helpers(tservice);
Mark Slee748e5762006-10-04 21:51:05 +0000819 generate_service_remote(tservice);
820
Mark Sleee50b3092006-09-04 00:06:47 +0000821 // Close service file
822 f_service_ << endl;
823 f_service_.close();
824}
825
826/**
827 * Generates helper functions for a service.
828 *
829 * @param tservice The service to generate a header definition for
830 */
831void t_py_generator::generate_service_helpers(t_service* tservice) {
832 vector<t_function*> functions = tservice->get_functions();
833 vector<t_function*>::iterator f_iter;
834
835 f_service_ <<
836 "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
837
838 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
839 t_struct* ts = (*f_iter)->get_arglist();
840 generate_py_struct_definition(f_service_, ts, false);
841 generate_py_function_helpers(*f_iter);
842 }
843}
844
845/**
846 * Generates a struct and helpers for a function.
847 *
848 * @param tfunction The function
849 */
850void t_py_generator::generate_py_function_helpers(t_function* tfunction) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000851 t_struct result(program_, tfunction->get_name() + "_result");
Mark Sleee50b3092006-09-04 00:06:47 +0000852 t_field success(tfunction->get_returntype(), "success", 0);
853 if (!tfunction->get_returntype()->is_void()) {
854 result.append(&success);
855 }
856
857 t_struct* xs = tfunction->get_xceptions();
858 const vector<t_field*>& fields = xs->get_members();
859 vector<t_field*>::const_iterator f_iter;
860 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
861 result.append(*f_iter);
862 }
Mark Sleee50b3092006-09-04 00:06:47 +0000863 generate_py_struct_definition(f_service_, &result, false, true);
864}
865
866/**
867 * Generates a service interface definition.
868 *
869 * @param tservice The service to generate a header definition for
870 */
871void t_py_generator::generate_service_interface(t_service* tservice) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000872 string extends = "";
873 string extends_if = "";
874 if (tservice->get_extends() != NULL) {
875 extends = type_name(tservice->get_extends());
876 extends_if = "(" + extends + ".Iface)";
877 }
878
Mark Sleee50b3092006-09-04 00:06:47 +0000879 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +0000880 "class Iface" << extends_if << ":" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000881 indent_up();
882 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +0000883 vector<t_function*>::iterator f_iter;
Mark Sleee50b3092006-09-04 00:06:47 +0000884 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
885 f_service_ <<
886 indent() << "def " << function_signature(*f_iter) << ":" << endl <<
887 indent() << " pass" << endl << endl;
888 }
889 indent_down();
890 f_service_ <<
891 endl;
892}
893
894/**
895 * Generates a service client definition.
896 *
897 * @param tservice The service to generate a server for.
898 */
899void t_py_generator::generate_service_client(t_service* tservice) {
Mark Sleef0712dc2006-10-25 19:03:57 +0000900 string extends = "";
901 string extends_client = "";
902 if (tservice->get_extends() != NULL) {
903 extends = type_name(tservice->get_extends());
904 extends_client = extends + ".Client, ";
905 }
906
Mark Sleee50b3092006-09-04 00:06:47 +0000907 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +0000908 "class Client(" << extends_client << "Iface):" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000909 indent_up();
910
911 // Constructor function
912 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000913 indent() << "def __init__(self, iprot, oprot=None):" << endl;
Mark Sleef0712dc2006-10-25 19:03:57 +0000914 if (extends.empty()) {
915 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000916 indent() << " self._iprot = self._oprot = iprot" << endl <<
917 indent() << " if oprot != None:" << endl <<
918 indent() << " self._oprot = oprot" << endl <<
Mark Sleef0712dc2006-10-25 19:03:57 +0000919 indent() << " self._seqid = 0" << endl <<
920 endl;
921 } else {
922 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000923 indent() << " " << extends << ".Client.__init__(self, iprot, oprot)" << endl <<
Mark Sleef0712dc2006-10-25 19:03:57 +0000924 endl;
925 }
Mark Sleee50b3092006-09-04 00:06:47 +0000926
927 // Generate client method implementations
928 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +0000929 vector<t_function*>::const_iterator f_iter;
Mark Sleee50b3092006-09-04 00:06:47 +0000930 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
931 t_struct* arg_struct = (*f_iter)->get_arglist();
932 const vector<t_field*>& fields = arg_struct->get_members();
933 vector<t_field*>::const_iterator fld_iter;
934 string funname = (*f_iter)->get_name();
935
936 // Open function
937 indent(f_service_) <<
938 "def " << function_signature(*f_iter) << ":" << endl;
939 indent_up();
940 indent(f_service_) <<
941 "self.send_" << funname << "(";
942
943 bool first = true;
944 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
945 if (first) {
946 first = false;
947 } else {
948 f_service_ << ", ";
949 }
950 f_service_ << (*fld_iter)->get_name();
951 }
952 f_service_ << ")" << endl;
953
954 if (!(*f_iter)->is_async()) {
955 f_service_ << indent();
956 if (!(*f_iter)->get_returntype()->is_void()) {
957 f_service_ << "return ";
958 }
959 f_service_ <<
960 "self.recv_" << funname << "()" << endl;
961 }
962 indent_down();
963 f_service_ << endl;
964
965 indent(f_service_) <<
966 "def send_" << function_signature(*f_iter) << ":" << endl;
967 indent_up();
968
969 std::string argsname = (*f_iter)->get_name() + "_args";
970
971 // Serialize the request header
972 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000973 indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000974
Mark Sleee50b3092006-09-04 00:06:47 +0000975 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000976 indent() << "args = " << argsname << "()" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000977
Mark Sleee50b3092006-09-04 00:06:47 +0000978 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
979 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000980 indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000981 }
David Reiss382fc302007-08-25 18:01:30 +0000982
Mark Sleee50b3092006-09-04 00:06:47 +0000983 // Write to the stream
984 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +0000985 indent() << "args.write(self._oprot)" << endl <<
986 indent() << "self._oprot.writeMessageEnd()" << endl <<
David Reiss382fc302007-08-25 18:01:30 +0000987 indent() << "self._oprot.trans.flush()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000988
989 indent_down();
Mark Sleee50b3092006-09-04 00:06:47 +0000990
991 if (!(*f_iter)->is_async()) {
992 std::string resultname = (*f_iter)->get_name() + "_result";
Mark Sleef0712dc2006-10-25 19:03:57 +0000993 t_struct noargs(program_);
David Reiss382fc302007-08-25 18:01:30 +0000994
Mark Sleee50b3092006-09-04 00:06:47 +0000995 t_function recv_function((*f_iter)->get_returntype(),
996 string("recv_") + (*f_iter)->get_name(),
997 &noargs);
998 // Open function
999 f_service_ <<
1000 endl <<
1001 indent() << "def " << function_signature(&recv_function) << ":" << endl;
1002 indent_up();
1003
Mark Sleef5377b32006-10-10 01:42:59 +00001004 // TODO(mcslee): Validate message reply here, seq ids etc.
Mark Sleee50b3092006-09-04 00:06:47 +00001005
1006 f_service_ <<
Mark Sleeb0060b02007-02-21 05:37:50 +00001007 indent() << "(fname, mtype, rseqid) = self._iprot.readMessageBegin()" << endl <<
1008 indent() << "if mtype == TMessageType.EXCEPTION:" << endl <<
1009 indent() << " x = TApplicationException()" << endl <<
1010 indent() << " x.read(self._iprot)" << endl <<
1011 indent() << " self._iprot.readMessageEnd()" << endl <<
1012 indent() << " raise x" << endl;
1013
1014 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001015 indent() << "result = " << resultname << "()" << endl <<
1016 indent() << "result.read(self._iprot)" << endl <<
1017 indent() << "self._iprot.readMessageEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001018
1019 // Careful, only return _result if not a void function
1020 if (!(*f_iter)->get_returntype()->is_void()) {
1021 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001022 indent() << "if result.success != None:" << endl <<
1023 indent() << " return result.success" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001024 }
1025
1026 t_struct* xs = (*f_iter)->get_xceptions();
1027 const std::vector<t_field*>& xceptions = xs->get_members();
1028 vector<t_field*>::const_iterator x_iter;
1029 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1030 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001031 indent() << "if result." << (*x_iter)->get_name() << " != None:" << endl <<
1032 indent() << " raise result." << (*x_iter)->get_name() << "" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001033 }
1034
1035 // Careful, only return _result if not a void function
1036 if ((*f_iter)->get_returntype()->is_void()) {
1037 indent(f_service_) <<
1038 "return" << endl;
1039 } else {
1040 f_service_ <<
Mark Sleeb0060b02007-02-21 05:37:50 +00001041 indent() << "raise TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001042 }
Mark Sleee50b3092006-09-04 00:06:47 +00001043
Mark Sleed07ce602006-10-27 22:30:15 +00001044 // Close function
1045 indent_down();
David Reiss382fc302007-08-25 18:01:30 +00001046 f_service_ << endl;
1047 }
Mark Sleee50b3092006-09-04 00:06:47 +00001048 }
1049
1050 indent_down();
1051 f_service_ <<
1052 endl;
1053}
1054
1055/**
Mark Slee748e5762006-10-04 21:51:05 +00001056 * Generates a command line tool for making remote requests
1057 *
1058 * @param tservice The service to generate a remote for.
1059 */
1060void t_py_generator::generate_service_remote(t_service* tservice) {
1061 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +00001062 vector<t_function*>::iterator f_iter;
Mark Slee748e5762006-10-04 21:51:05 +00001063
Mark Sleeecf490e2007-02-21 00:05:18 +00001064 string f_remote_name = package_dir_+"/"+service_name_+"-remote";
Mark Slee748e5762006-10-04 21:51:05 +00001065 ofstream f_remote;
1066 f_remote.open(f_remote_name.c_str());
1067
1068 f_remote <<
Mark Slee2c2a6482007-02-21 00:22:33 +00001069 "#!/usr/bin/env python" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001070 py_autogen_comment() << endl <<
1071 "import sys" << endl <<
1072 "import pprint" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001073 "from urlparse import urlparse" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001074 "from thrift.transport import TTransport" << endl <<
1075 "from thrift.transport import TSocket" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001076 "from thrift.transport import THttpClient" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001077 "from thrift.protocol import TBinaryProtocol" << endl <<
1078 endl;
1079
1080 f_remote <<
1081 "import " << service_name_ << endl <<
David Reiss382fc302007-08-25 18:01:30 +00001082 "from ttypes import *" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001083 endl;
1084
1085 f_remote <<
1086 "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl <<
1087 " print ''" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001088 " print 'Usage: ' + sys.argv[0] + ' [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]'" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001089 " print ''" << endl <<
1090 " print 'Functions:'" << endl;
1091 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1092 f_remote <<
1093 " print ' " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "(";
1094 t_struct* arg_struct = (*f_iter)->get_arglist();
1095 const std::vector<t_field*>& args = arg_struct->get_members();
1096 vector<t_field*>::const_iterator a_iter;
1097 int num_args = args.size();
1098 bool first = true;
1099 for (int i = 0; i < num_args; ++i) {
1100 if (first) {
1101 first = false;
1102 } else {
1103 f_remote << ", ";
1104 }
David Reiss382fc302007-08-25 18:01:30 +00001105 f_remote <<
Mark Slee748e5762006-10-04 21:51:05 +00001106 args[i]->get_type()->get_name() << " " << args[i]->get_name();
1107 }
1108 f_remote << ")'" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001109 }
Mark Slee748e5762006-10-04 21:51:05 +00001110 f_remote <<
1111 " print ''" << endl <<
1112 " sys.exit(0)" << endl <<
1113 endl;
1114
1115 f_remote <<
1116 "pp = pprint.PrettyPrinter(indent = 2)" << endl <<
1117 "host = 'localhost'" << endl <<
Mark Slee96a6bbe2006-10-06 22:43:29 +00001118 "port = 9090" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001119 "uri = ''" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001120 "framed = False" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001121 "http = False" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001122 "argi = 1" << endl <<
1123 endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001124 "if sys.argv[argi] == '-h':" << endl <<
1125 " parts = sys.argv[argi+1].split(':') " << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001126 " host = parts[0]" << endl <<
1127 " port = int(parts[1])" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001128 " argi += 2" << endl <<
1129 endl <<
1130 "if sys.argv[argi] == '-u':" << endl <<
1131 " url = urlparse(sys.argv[argi+1])" << endl <<
1132 " parts = url[1].split(':') " << endl <<
1133 " host = parts[0]" << endl <<
1134 " if len(parts) > 1:" << endl <<
1135 " port = int(parts[1])" << endl <<
1136 " else:" << endl <<
1137 " port = 80" << endl <<
1138 " uri = url[2]" << endl <<
1139 " http = True" << endl <<
1140 " argi += 2" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001141 endl <<
1142 "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl <<
1143 " framed = True" << endl <<
1144 " argi += 1" << endl <<
1145 endl <<
1146 "cmd = sys.argv[argi]" << endl <<
1147 "args = sys.argv[argi+1:]" << endl <<
1148 endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001149 "if http:" << endl <<
1150 " transport = THttpClient.THttpClient(host, port, uri)" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001151 "else:" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001152 " socket = TSocket.TSocket(host, port)" << endl <<
1153 " if framed:" << endl <<
1154 " transport = TTransport.TFramedTransport(socket)" << endl <<
1155 " else:" << endl <<
1156 " transport = TTransport.TBufferedTransport(socket)" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001157 "protocol = TBinaryProtocol.TBinaryProtocol(transport)" << endl <<
1158 "client = " << service_name_ << ".Client(protocol)" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001159 "transport.open()" << endl <<
1160 endl;
David Reiss382fc302007-08-25 18:01:30 +00001161
Mark Slee748e5762006-10-04 21:51:05 +00001162 // Generate the dispatch methods
1163 bool first = true;
1164
1165 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1166 if (first) {
1167 first = false;
1168 } else {
1169 f_remote << "el";
1170 }
1171
1172 t_struct* arg_struct = (*f_iter)->get_arglist();
1173 const std::vector<t_field*>& args = arg_struct->get_members();
1174 vector<t_field*>::const_iterator a_iter;
1175 int num_args = args.size();
1176
1177 f_remote <<
1178 "if cmd == '" << (*f_iter)->get_name() << "':" << endl <<
1179 " if len(args) != " << num_args << ":" << endl <<
1180 " print '" << (*f_iter)->get_name() << " requires " << num_args << " args'" << endl <<
1181 " sys.exit(1)" << endl <<
1182 " pp.pprint(client." << (*f_iter)->get_name() << "(";
1183 for (int i = 0; i < num_args; ++i) {
Mark Sleeb6200d82007-01-19 19:14:36 +00001184 if (args[i]->get_type()->is_string()) {
Mark Slee748e5762006-10-04 21:51:05 +00001185 f_remote << "args[" << i << "],";
Mark Slee96a6bbe2006-10-06 22:43:29 +00001186 } else {
1187 f_remote << "eval(args[" << i << "]),";
Mark Slee748e5762006-10-04 21:51:05 +00001188 }
1189 }
1190 f_remote << "))" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001191
Mark Slee748e5762006-10-04 21:51:05 +00001192 f_remote << endl;
1193 }
1194
1195 f_remote << "transport.close()" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001196
Mark Slee748e5762006-10-04 21:51:05 +00001197 // Close service file
1198 f_remote.close();
David Reiss382fc302007-08-25 18:01:30 +00001199
Mark Sleef5377b32006-10-10 01:42:59 +00001200 // Make file executable, love that bitwise OR action
Mark Slee748e5762006-10-04 21:51:05 +00001201 chmod(f_remote_name.c_str(),
David Reiss204420f2008-01-11 20:59:03 +00001202 S_IRUSR
1203 | S_IWUSR
1204 | S_IXUSR
1205#ifndef MINGW
1206 | S_IRGRP
1207 | S_IXGRP
1208 | S_IROTH
1209 | S_IXOTH
1210#endif
David Reiss0c90f6f2008-02-06 22:18:40 +00001211 );
Mark Slee748e5762006-10-04 21:51:05 +00001212}
1213
1214/**
Mark Sleec9676562006-09-05 17:34:52 +00001215 * Generates a service server definition.
1216 *
1217 * @param tservice The service to generate a server for.
1218 */
1219void t_py_generator::generate_service_server(t_service* tservice) {
1220 // Generate the dispatch methods
1221 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +00001222 vector<t_function*>::iterator f_iter;
Mark Sleec9676562006-09-05 17:34:52 +00001223
Mark Sleef0712dc2006-10-25 19:03:57 +00001224 string extends = "";
1225 string extends_processor = "";
1226 if (tservice->get_extends() != NULL) {
1227 extends = type_name(tservice->get_extends());
1228 extends_processor = extends + ".Processor, ";
1229 }
1230
Mark Sleec9676562006-09-05 17:34:52 +00001231 // Generate the header portion
1232 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001233 "class Processor(" << extends_processor << "Iface, TProcessor):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001234 indent_up();
1235
1236 indent(f_service_) <<
Mark Slee5946a182006-10-25 21:38:39 +00001237 "def __init__(self, handler):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001238 indent_up();
Mark Sleef0712dc2006-10-25 19:03:57 +00001239 if (extends.empty()) {
1240 f_service_ <<
1241 indent() << "self._handler = handler" << endl <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001242 indent() << "self._processMap = {}" << endl;
Mark Slee6b4783b2006-10-31 05:43:53 +00001243 } else {
1244 f_service_ <<
Mark Sleebc4bc0f2006-10-31 05:45:33 +00001245 indent() << extends << ".Processor.__init__(self, handler)" << endl;
Mark Sleef0712dc2006-10-25 19:03:57 +00001246 }
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001247 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1248 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001249 indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
David Reiss382fc302007-08-25 18:01:30 +00001250 }
Mark Sleec9676562006-09-05 17:34:52 +00001251 indent_down();
1252 f_service_ << endl;
David Reiss382fc302007-08-25 18:01:30 +00001253
Mark Sleec9676562006-09-05 17:34:52 +00001254 // Generate the server implementation
1255 indent(f_service_) <<
Mark Slee5946a182006-10-25 21:38:39 +00001256 "def process(self, iprot, oprot):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001257 indent_up();
1258
1259 f_service_ <<
Mark Sleeb0060b02007-02-21 05:37:50 +00001260 indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001261
1262 // TODO(mcslee): validate message
1263
Mark Sleef5377b32006-10-10 01:42:59 +00001264 // HOT: dictionary function lookup
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001265 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001266 indent() << "if name not in self._processMap:" << endl <<
Mark Sleeb0060b02007-02-21 05:37:50 +00001267 indent() << " iprot.skip(TType.STRUCT)" << endl <<
1268 indent() << " iprot.readMessageEnd()" << endl <<
1269 indent() << " x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))" << endl <<
1270 indent() << " oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl <<
1271 indent() << " x.write(oprot)" << endl <<
1272 indent() << " oprot.writeMessageEnd()" << endl <<
1273 indent() << " oprot.trans.flush()" << endl <<
1274 indent() << " return" << endl <<
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001275 indent() << "else:" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001276 indent() << " self._processMap[name](self, seqid, iprot, oprot)" << endl;
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001277
Mark Sleec9676562006-09-05 17:34:52 +00001278 // Read end of args field, the T_STOP, and the struct close
1279 f_service_ <<
1280 indent() << "return True" << endl;
1281
1282 indent_down();
1283 f_service_ << endl;
1284
1285 // Generate the process subfunctions
1286 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1287 generate_process_function(tservice, *f_iter);
1288 }
1289
1290 indent_down();
1291 f_service_ << endl;
1292}
1293
1294/**
1295 * Generates a process function definition.
1296 *
1297 * @param tfunction The function to write a dispatcher for
1298 */
1299void t_py_generator::generate_process_function(t_service* tservice,
1300 t_function* tfunction) {
1301 // Open function
1302 indent(f_service_) <<
1303 "def process_" << tfunction->get_name() <<
Mark Slee5946a182006-10-25 21:38:39 +00001304 "(self, seqid, iprot, oprot):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001305 indent_up();
1306
1307 string argsname = tfunction->get_name() + "_args";
1308 string resultname = tfunction->get_name() + "_result";
1309
1310 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001311 indent() << "args = " << argsname << "()" << endl <<
1312 indent() << "args.read(iprot)" << endl <<
1313 indent() << "iprot.readMessageEnd()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001314
1315 t_struct* xs = tfunction->get_xceptions();
1316 const std::vector<t_field*>& xceptions = xs->get_members();
1317 vector<t_field*>::const_iterator x_iter;
1318
1319 // Declare result for non async function
1320 if (!tfunction->is_async()) {
1321 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001322 indent() << "result = " << resultname << "()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001323 }
1324
1325 // Try block for a function with exceptions
1326 if (xceptions.size() > 0) {
1327 f_service_ <<
1328 indent() << "try:" << endl;
1329 indent_up();
1330 }
David Reiss382fc302007-08-25 18:01:30 +00001331
Mark Sleec9676562006-09-05 17:34:52 +00001332 // Generate the function call
1333 t_struct* arg_struct = tfunction->get_arglist();
1334 const std::vector<t_field*>& fields = arg_struct->get_members();
1335 vector<t_field*>::const_iterator f_iter;
1336
1337 f_service_ << indent();
1338 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
Mark Slee5946a182006-10-25 21:38:39 +00001339 f_service_ << "result.success = ";
Mark Sleec9676562006-09-05 17:34:52 +00001340 }
1341 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001342 "self._handler." << tfunction->get_name() << "(";
Mark Sleec9676562006-09-05 17:34:52 +00001343 bool first = true;
1344 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1345 if (first) {
1346 first = false;
1347 } else {
1348 f_service_ << ", ";
1349 }
Mark Slee5946a182006-10-25 21:38:39 +00001350 f_service_ << "args." << (*f_iter)->get_name();
Mark Sleec9676562006-09-05 17:34:52 +00001351 }
1352 f_service_ << ")" << endl;
1353
1354 if (!tfunction->is_async() && xceptions.size() > 0) {
1355 indent_down();
1356 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1357 f_service_ <<
Mark Slee6341d132008-09-29 22:01:30 +00001358 indent() << "except " << type_name((*x_iter)->get_type()) << ", " << (*x_iter)->get_name() << ":" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001359 if (!tfunction->is_async()) {
1360 indent_up();
1361 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001362 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001363 indent_down();
1364 } else {
1365 f_service_ <<
1366 indent() << "pass" << endl;
1367 }
1368 }
1369 }
1370
1371 // Shortcut out here for async functions
1372 if (tfunction->is_async()) {
1373 f_service_ <<
1374 indent() << "return" << endl;
1375 indent_down();
1376 f_service_ << endl;
1377 return;
1378 }
1379
1380 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001381 indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
1382 indent() << "result.write(oprot)" << endl <<
1383 indent() << "oprot.writeMessageEnd()" << endl <<
Mark Slee9f8361f2007-02-09 02:14:43 +00001384 indent() << "oprot.trans.flush()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001385
1386 // Close function
1387 indent_down();
1388 f_service_ << endl;
1389}
1390
1391/**
Mark Sleee50b3092006-09-04 00:06:47 +00001392 * Deserializes a field of any type.
1393 */
1394void t_py_generator::generate_deserialize_field(ofstream &out,
1395 t_field* tfield,
1396 string prefix,
1397 bool inclass) {
David Reisse087a302007-08-23 21:43:25 +00001398 t_type* type = get_true_type(tfield->get_type());
Mark Sleee50b3092006-09-04 00:06:47 +00001399
1400 if (type->is_void()) {
1401 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1402 prefix + tfield->get_name();
1403 }
1404
1405 string name = prefix + tfield->get_name();
1406
1407 if (type->is_struct() || type->is_xception()) {
1408 generate_deserialize_struct(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001409 (t_struct*)type,
Mark Sleee50b3092006-09-04 00:06:47 +00001410 name);
1411 } else if (type->is_container()) {
Mark Slee216e7d62006-11-21 00:44:23 +00001412 generate_deserialize_container(out, type, name);
Mark Sleee50b3092006-09-04 00:06:47 +00001413 } else if (type->is_base_type() || type->is_enum()) {
1414 indent(out) <<
1415 name << " = iprot.";
David Reiss382fc302007-08-25 18:01:30 +00001416
Mark Sleee50b3092006-09-04 00:06:47 +00001417 if (type->is_base_type()) {
1418 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1419 switch (tbase) {
1420 case t_base_type::TYPE_VOID:
1421 throw "compiler error: cannot serialize void field in a struct: " +
1422 name;
1423 break;
David Reiss382fc302007-08-25 18:01:30 +00001424 case t_base_type::TYPE_STRING:
Mark Slee5946a182006-10-25 21:38:39 +00001425 out << "readString();";
Mark Sleee50b3092006-09-04 00:06:47 +00001426 break;
1427 case t_base_type::TYPE_BOOL:
Mark Slee5946a182006-10-25 21:38:39 +00001428 out << "readBool();";
Mark Sleee50b3092006-09-04 00:06:47 +00001429 break;
1430 case t_base_type::TYPE_BYTE:
Mark Slee5946a182006-10-25 21:38:39 +00001431 out << "readByte();";
Mark Sleee50b3092006-09-04 00:06:47 +00001432 break;
1433 case t_base_type::TYPE_I16:
Mark Slee5946a182006-10-25 21:38:39 +00001434 out << "readI16();";
Mark Sleee50b3092006-09-04 00:06:47 +00001435 break;
1436 case t_base_type::TYPE_I32:
Mark Slee5946a182006-10-25 21:38:39 +00001437 out << "readI32();";
Mark Sleee50b3092006-09-04 00:06:47 +00001438 break;
1439 case t_base_type::TYPE_I64:
Mark Slee5946a182006-10-25 21:38:39 +00001440 out << "readI64();";
Mark Sleee50b3092006-09-04 00:06:47 +00001441 break;
Mark Sleec98d0502006-09-06 02:42:25 +00001442 case t_base_type::TYPE_DOUBLE:
Mark Slee5946a182006-10-25 21:38:39 +00001443 out << "readDouble();";
Mark Sleec98d0502006-09-06 02:42:25 +00001444 break;
Mark Sleee50b3092006-09-04 00:06:47 +00001445 default:
David Reissdd7796f2007-08-28 21:09:06 +00001446 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Mark Sleee50b3092006-09-04 00:06:47 +00001447 }
1448 } else if (type->is_enum()) {
Mark Slee5946a182006-10-25 21:38:39 +00001449 out << "readI32();";
Mark Sleee50b3092006-09-04 00:06:47 +00001450 }
1451 out << endl;
1452
1453 } else {
1454 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
Mark Sleef5377b32006-10-10 01:42:59 +00001455 tfield->get_name().c_str(), type->get_name().c_str());
David Reiss382fc302007-08-25 18:01:30 +00001456 }
Mark Sleee50b3092006-09-04 00:06:47 +00001457}
1458
1459/**
Mark Sleef5377b32006-10-10 01:42:59 +00001460 * Generates an unserializer for a struct, calling read()
Mark Sleee50b3092006-09-04 00:06:47 +00001461 */
1462void t_py_generator::generate_deserialize_struct(ofstream &out,
1463 t_struct* tstruct,
1464 string prefix) {
1465 out <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001466 indent() << prefix << " = " << type_name(tstruct) << "()" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001467 indent() << prefix << ".read(iprot)" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001468}
1469
Mark Sleef5377b32006-10-10 01:42:59 +00001470/**
1471 * Serialize a container by writing out the header followed by
1472 * data and then a footer.
1473 */
Mark Sleee50b3092006-09-04 00:06:47 +00001474void t_py_generator::generate_deserialize_container(ofstream &out,
Mark Sleeaeac1922006-09-04 00:20:24 +00001475 t_type* ttype,
1476 string prefix) {
Mark Sleee50b3092006-09-04 00:06:47 +00001477 string size = tmp("_size");
1478 string ktype = tmp("_ktype");
1479 string vtype = tmp("_vtype");
1480 string etype = tmp("_etype");
David Reiss382fc302007-08-25 18:01:30 +00001481
Mark Sleef0712dc2006-10-25 19:03:57 +00001482 t_field fsize(g_type_i32, size);
1483 t_field fktype(g_type_byte, ktype);
1484 t_field fvtype(g_type_byte, vtype);
1485 t_field fetype(g_type_byte, etype);
Mark Sleee50b3092006-09-04 00:06:47 +00001486
1487 // Declare variables, read header
1488 if (ttype->is_map()) {
1489 out <<
Mark Sleeaeac1922006-09-04 00:20:24 +00001490 indent() << prefix << " = {}" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001491 indent() << "(" << ktype << ", " << vtype << ", " << size << " ) = iprot.readMapBegin() " << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001492 } else if (ttype->is_set()) {
1493 out <<
Mark Slee600cdb32006-11-29 22:06:42 +00001494 indent() << prefix << " = set()" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001495 indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001496 } else if (ttype->is_list()) {
1497 out <<
Mark Sleeaeac1922006-09-04 00:20:24 +00001498 indent() << prefix << " = []" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001499 indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001500 }
1501
1502 // For loop iterates over elements
1503 string i = tmp("_i");
1504 indent(out) <<
1505 "for " << i << " in xrange(" << size << "):" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001506
Mark Sleee50b3092006-09-04 00:06:47 +00001507 indent_up();
David Reiss382fc302007-08-25 18:01:30 +00001508
Mark Sleee50b3092006-09-04 00:06:47 +00001509 if (ttype->is_map()) {
1510 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
1511 } else if (ttype->is_set()) {
1512 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
1513 } else if (ttype->is_list()) {
1514 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
1515 }
David Reiss382fc302007-08-25 18:01:30 +00001516
Mark Sleee50b3092006-09-04 00:06:47 +00001517 indent_down();
1518
1519 // Read container end
1520 if (ttype->is_map()) {
Mark Slee5946a182006-10-25 21:38:39 +00001521 indent(out) << "iprot.readMapEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001522 } else if (ttype->is_set()) {
Mark Slee5946a182006-10-25 21:38:39 +00001523 indent(out) << "iprot.readSetEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001524 } else if (ttype->is_list()) {
Mark Slee5946a182006-10-25 21:38:39 +00001525 indent(out) << "iprot.readListEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001526 }
1527}
1528
1529
1530/**
1531 * Generates code to deserialize a map
1532 */
1533void t_py_generator::generate_deserialize_map_element(ofstream &out,
1534 t_map* tmap,
1535 string prefix) {
1536 string key = tmp("_key");
1537 string val = tmp("_val");
1538 t_field fkey(tmap->get_key_type(), key);
1539 t_field fval(tmap->get_val_type(), val);
1540
Mark Sleee50b3092006-09-04 00:06:47 +00001541 generate_deserialize_field(out, &fkey);
1542 generate_deserialize_field(out, &fval);
1543
1544 indent(out) <<
1545 prefix << "[" << key << "] = " << val << endl;
1546}
1547
Mark Sleef5377b32006-10-10 01:42:59 +00001548/**
1549 * Write a set element
1550 */
Mark Sleee50b3092006-09-04 00:06:47 +00001551void t_py_generator::generate_deserialize_set_element(ofstream &out,
1552 t_set* tset,
1553 string prefix) {
1554 string elem = tmp("_elem");
1555 t_field felem(tset->get_elem_type(), elem);
1556
Mark Sleee50b3092006-09-04 00:06:47 +00001557 generate_deserialize_field(out, &felem);
1558
1559 indent(out) <<
Mark Slee600cdb32006-11-29 22:06:42 +00001560 prefix << ".add(" << elem << ")" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001561}
1562
Mark Sleef5377b32006-10-10 01:42:59 +00001563/**
1564 * Write a list element
1565 */
Mark Sleee50b3092006-09-04 00:06:47 +00001566void t_py_generator::generate_deserialize_list_element(ofstream &out,
1567 t_list* tlist,
1568 string prefix) {
1569 string elem = tmp("_elem");
1570 t_field felem(tlist->get_elem_type(), elem);
1571
Mark Sleee50b3092006-09-04 00:06:47 +00001572 generate_deserialize_field(out, &felem);
1573
1574 indent(out) <<
1575 prefix << ".append(" << elem << ")" << endl;
1576}
1577
1578
1579/**
1580 * Serializes a field of any type.
1581 *
1582 * @param tfield The field to serialize
1583 * @param prefix Name to prepend to field name
1584 */
1585void t_py_generator::generate_serialize_field(ofstream &out,
1586 t_field* tfield,
1587 string prefix) {
David Reisse087a302007-08-23 21:43:25 +00001588 t_type* type = get_true_type(tfield->get_type());
Mark Sleee50b3092006-09-04 00:06:47 +00001589
1590 // Do nothing for void types
1591 if (type->is_void()) {
1592 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1593 prefix + tfield->get_name();
1594 }
David Reiss382fc302007-08-25 18:01:30 +00001595
Mark Sleee50b3092006-09-04 00:06:47 +00001596 if (type->is_struct() || type->is_xception()) {
1597 generate_serialize_struct(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001598 (t_struct*)type,
Mark Sleee50b3092006-09-04 00:06:47 +00001599 prefix + tfield->get_name());
1600 } else if (type->is_container()) {
1601 generate_serialize_container(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001602 type,
Mark Sleee50b3092006-09-04 00:06:47 +00001603 prefix + tfield->get_name());
1604 } else if (type->is_base_type() || type->is_enum()) {
1605
1606 string name = prefix + tfield->get_name();
1607
1608 indent(out) <<
1609 "oprot.";
David Reiss382fc302007-08-25 18:01:30 +00001610
Mark Sleee50b3092006-09-04 00:06:47 +00001611 if (type->is_base_type()) {
1612 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1613 switch (tbase) {
1614 case t_base_type::TYPE_VOID:
1615 throw
1616 "compiler error: cannot serialize void field in a struct: " + name;
1617 break;
1618 case t_base_type::TYPE_STRING:
Mark Slee5946a182006-10-25 21:38:39 +00001619 out << "writeString(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001620 break;
1621 case t_base_type::TYPE_BOOL:
Mark Slee5946a182006-10-25 21:38:39 +00001622 out << "writeBool(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001623 break;
1624 case t_base_type::TYPE_BYTE:
Mark Slee5946a182006-10-25 21:38:39 +00001625 out << "writeByte(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001626 break;
1627 case t_base_type::TYPE_I16:
Mark Slee5946a182006-10-25 21:38:39 +00001628 out << "writeI16(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001629 break;
1630 case t_base_type::TYPE_I32:
Mark Slee5946a182006-10-25 21:38:39 +00001631 out << "writeI32(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001632 break;
1633 case t_base_type::TYPE_I64:
Mark Slee5946a182006-10-25 21:38:39 +00001634 out << "writeI64(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001635 break;
Mark Sleec98d0502006-09-06 02:42:25 +00001636 case t_base_type::TYPE_DOUBLE:
Mark Slee5946a182006-10-25 21:38:39 +00001637 out << "writeDouble(" << name << ")";
Mark Sleec98d0502006-09-06 02:42:25 +00001638 break;
Mark Sleee50b3092006-09-04 00:06:47 +00001639 default:
David Reissdd7796f2007-08-28 21:09:06 +00001640 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Mark Sleee50b3092006-09-04 00:06:47 +00001641 }
1642 } else if (type->is_enum()) {
Mark Slee5946a182006-10-25 21:38:39 +00001643 out << "writeI32(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00001644 }
1645 out << endl;
1646 } else {
1647 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1648 prefix.c_str(),
1649 tfield->get_name().c_str(),
Mark Sleef5377b32006-10-10 01:42:59 +00001650 type->get_name().c_str());
Mark Sleee50b3092006-09-04 00:06:47 +00001651 }
1652}
1653
1654/**
1655 * Serializes all the members of a struct.
1656 *
1657 * @param tstruct The struct to serialize
1658 * @param prefix String prefix to attach to all fields
1659 */
1660void t_py_generator::generate_serialize_struct(ofstream &out,
Mark Sleef5377b32006-10-10 01:42:59 +00001661 t_struct* tstruct,
1662 string prefix) {
Mark Sleee50b3092006-09-04 00:06:47 +00001663 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001664 prefix << ".write(oprot)" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001665}
1666
1667void t_py_generator::generate_serialize_container(ofstream &out,
Mark Sleef5377b32006-10-10 01:42:59 +00001668 t_type* ttype,
1669 string prefix) {
Mark Sleee50b3092006-09-04 00:06:47 +00001670 if (ttype->is_map()) {
1671 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001672 "oprot.writeMapBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +00001673 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
1674 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
1675 "len(" << prefix << "))" << endl;
1676 } else if (ttype->is_set()) {
1677 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001678 "oprot.writeSetBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +00001679 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
1680 "len(" << prefix << "))" << endl;
1681 } else if (ttype->is_list()) {
1682 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001683 "oprot.writeListBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +00001684 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
1685 "len(" << prefix << "))" << endl;
1686 }
1687
Mark Sleef5377b32006-10-10 01:42:59 +00001688 if (ttype->is_map()) {
Mark Sleeb39dbc52006-10-31 05:56:27 +00001689 string kiter = tmp("kiter");
1690 string viter = tmp("viter");
David Reiss382fc302007-08-25 18:01:30 +00001691 indent(out) <<
Mark Sleeb39dbc52006-10-31 05:56:27 +00001692 "for " << kiter << "," << viter << " in " << prefix << ".items():" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00001693 indent_up();
1694 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
1695 indent_down();
1696 } else if (ttype->is_set()) {
Mark Sleeb39dbc52006-10-31 05:56:27 +00001697 string iter = tmp("iter");
David Reiss382fc302007-08-25 18:01:30 +00001698 indent(out) <<
Mark Sleef5377b32006-10-10 01:42:59 +00001699 "for " << iter << " in " << prefix << ":" << endl;
1700 indent_up();
1701 generate_serialize_set_element(out, (t_set*)ttype, iter);
1702 indent_down();
1703 } else if (ttype->is_list()) {
Mark Sleeb39dbc52006-10-31 05:56:27 +00001704 string iter = tmp("iter");
David Reiss382fc302007-08-25 18:01:30 +00001705 indent(out) <<
Mark Sleef5377b32006-10-10 01:42:59 +00001706 "for " << iter << " in " << prefix << ":" << endl;
1707 indent_up();
1708 generate_serialize_list_element(out, (t_list*)ttype, iter);
1709 indent_down();
1710 }
David Reiss382fc302007-08-25 18:01:30 +00001711
Mark Sleee50b3092006-09-04 00:06:47 +00001712 if (ttype->is_map()) {
1713 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001714 "oprot.writeMapEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001715 } else if (ttype->is_set()) {
1716 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001717 "oprot.writeSetEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001718 } else if (ttype->is_list()) {
1719 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00001720 "oprot.writeListEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001721 }
1722}
1723
1724/**
1725 * Serializes the members of a map.
1726 *
1727 */
1728void t_py_generator::generate_serialize_map_element(ofstream &out,
1729 t_map* tmap,
1730 string kiter,
1731 string viter) {
1732 t_field kfield(tmap->get_key_type(), kiter);
1733 generate_serialize_field(out, &kfield, "");
1734
1735 t_field vfield(tmap->get_val_type(), viter);
1736 generate_serialize_field(out, &vfield, "");
1737}
1738
1739/**
1740 * Serializes the members of a set.
1741 */
1742void t_py_generator::generate_serialize_set_element(ofstream &out,
1743 t_set* tset,
1744 string iter) {
1745 t_field efield(tset->get_elem_type(), iter);
1746 generate_serialize_field(out, &efield, "");
1747}
1748
1749/**
1750 * Serializes the members of a list.
1751 */
1752void t_py_generator::generate_serialize_list_element(ofstream &out,
1753 t_list* tlist,
1754 string iter) {
1755 t_field efield(tlist->get_elem_type(), iter);
1756 generate_serialize_field(out, &efield, "");
1757}
1758
1759/**
Mark Sleee50b3092006-09-04 00:06:47 +00001760 * Declares a field, which may include initialization as necessary.
1761 *
1762 * @param ttype The type
1763 */
Mark Slee7ff32452007-02-01 05:26:18 +00001764string t_py_generator::declare_field(t_field* tfield) {
Mark Sleee50b3092006-09-04 00:06:47 +00001765 string result = "self." + tfield->get_name();
David Reisse087a302007-08-23 21:43:25 +00001766 t_type* type = get_true_type(tfield->get_type());
Mark Slee7ff32452007-02-01 05:26:18 +00001767 if (tfield->get_value() != NULL) {
1768 result += " = " + render_const_value(type, tfield->get_value());
1769 } else {
1770 result += " = None";
Mark Sleee50b3092006-09-04 00:06:47 +00001771 }
1772 return result;
1773}
1774
1775/**
1776 * Renders a function signature of the form 'type name(args)'
1777 *
1778 * @param tfunction Function definition
1779 * @return String of rendered function definition
1780 */
1781string t_py_generator::function_signature(t_function* tfunction,
1782 string prefix) {
Mark Sleef5377b32006-10-10 01:42:59 +00001783 // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
Mark Sleee50b3092006-09-04 00:06:47 +00001784 return
1785 prefix + tfunction->get_name() +
1786 "(self, " + argument_list(tfunction->get_arglist()) + ")";
1787}
1788
1789/**
1790 * Renders a field list
1791 */
1792string t_py_generator::argument_list(t_struct* tstruct) {
1793 string result = "";
1794
1795 const vector<t_field*>& fields = tstruct->get_members();
1796 vector<t_field*>::const_iterator f_iter;
1797 bool first = true;
1798 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1799 if (first) {
1800 first = false;
1801 } else {
1802 result += ", ";
1803 }
1804 result += (*f_iter)->get_name();
1805 }
1806 return result;
1807}
1808
Mark Sleef0712dc2006-10-25 19:03:57 +00001809string t_py_generator::type_name(t_type* ttype) {
1810 t_program* program = ttype->get_program();
1811 if (program != NULL && program != program_) {
1812 if (ttype->is_service()) {
David Reissc6fc3292007-08-30 00:58:43 +00001813 return get_real_py_module(program) + "." + ttype->get_name();
Mark Sleef0712dc2006-10-25 19:03:57 +00001814 } else {
David Reissc6fc3292007-08-30 00:58:43 +00001815 return get_real_py_module(program) + ".ttypes." + ttype->get_name();
Mark Sleef0712dc2006-10-25 19:03:57 +00001816 }
1817 }
1818 return ttype->get_name();
1819}
1820
Mark Sleee50b3092006-09-04 00:06:47 +00001821/**
Mark Sleef5377b32006-10-10 01:42:59 +00001822 * Converts the parse type to a Python tyoe
Mark Sleee50b3092006-09-04 00:06:47 +00001823 */
1824string t_py_generator::type_to_enum(t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00001825 type = get_true_type(type);
David Reiss382fc302007-08-25 18:01:30 +00001826
Mark Sleee50b3092006-09-04 00:06:47 +00001827 if (type->is_base_type()) {
1828 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1829 switch (tbase) {
1830 case t_base_type::TYPE_VOID:
1831 throw "NO T_VOID CONSTRUCT";
1832 case t_base_type::TYPE_STRING:
1833 return "TType.STRING";
1834 case t_base_type::TYPE_BOOL:
1835 return "TType.BOOL";
1836 case t_base_type::TYPE_BYTE:
1837 return "TType.BYTE";
1838 case t_base_type::TYPE_I16:
1839 return "TType.I16";
1840 case t_base_type::TYPE_I32:
1841 return "TType.I32";
1842 case t_base_type::TYPE_I64:
1843 return "TType.I64";
Mark Sleec98d0502006-09-06 02:42:25 +00001844 case t_base_type::TYPE_DOUBLE:
1845 return "TType.DOUBLE";
Mark Sleee50b3092006-09-04 00:06:47 +00001846 }
1847 } else if (type->is_enum()) {
1848 return "TType.I32";
1849 } else if (type->is_struct() || type->is_xception()) {
1850 return "TType.STRUCT";
1851 } else if (type->is_map()) {
1852 return "TType.MAP";
1853 } else if (type->is_set()) {
1854 return "TType.SET";
1855 } else if (type->is_list()) {
1856 return "TType.LIST";
1857 }
1858
1859 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1860}
David Reiss382fc302007-08-25 18:01:30 +00001861
1862/** See the comment inside generate_py_struct_definition for what this is. */
1863string t_py_generator::type_to_spec_args(t_type* ttype) {
1864 while (ttype->is_typedef()) {
1865 ttype = ((t_typedef*)ttype)->get_type();
1866 }
1867
1868 if (ttype->is_base_type() || ttype->is_enum()) {
1869 return "None";
1870 } else if (ttype->is_struct() || ttype->is_xception()) {
1871 return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)";
1872 } else if (ttype->is_map()) {
1873 return "(" +
1874 type_to_enum(((t_map*)ttype)->get_key_type()) + "," +
1875 type_to_spec_args(((t_map*)ttype)->get_key_type()) + "," +
1876 type_to_enum(((t_map*)ttype)->get_val_type()) + "," +
1877 type_to_spec_args(((t_map*)ttype)->get_val_type()) +
1878 ")";
1879
1880 } else if (ttype->is_set()) {
1881 return "(" +
1882 type_to_enum(((t_set*)ttype)->get_elem_type()) + "," +
1883 type_to_spec_args(((t_set*)ttype)->get_elem_type()) +
1884 ")";
1885
1886 } else if (ttype->is_list()) {
1887 return "(" +
1888 type_to_enum(((t_list*)ttype)->get_elem_type()) + "," +
1889 type_to_spec_args(((t_list*)ttype)->get_elem_type()) +
1890 ")";
1891 }
1892
1893 throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
1894}
David Reiss558e3992008-03-27 21:41:40 +00001895
1896
1897THRIFT_REGISTER_GENERATOR(py, "Python",
1898" new_style: Generate new-style classes.\n"
1899);