blob: 44623054077d48990c46819637d466c3cfccada9 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Mark Sleee9ce01c2007-05-16 02:29:53 +000019
David Reiss0d6eb962008-03-27 21:41:45 +000020#include <string>
21#include <fstream>
22#include <iostream>
23#include <vector>
24
Mark Sleee50b3092006-09-04 00:06:47 +000025#include <stdlib.h>
26#include <sys/stat.h>
Mark Slee748e5762006-10-04 21:51:05 +000027#include <sys/types.h>
Mark Sleee50b3092006-09-04 00:06:47 +000028#include <sstream>
David Reiss382fc302007-08-25 18:01:30 +000029#include <algorithm>
David Reiss0d6eb962008-03-27 21:41:45 +000030#include "t_generator.h"
David Reiss204420f2008-01-11 20:59:03 +000031#include "platform.h"
Roger Meier08d46812011-04-12 19:08:21 +000032#include "version.h"
33
Mark Sleee50b3092006-09-04 00:06:47 +000034using namespace std;
35
David Reiss0d6eb962008-03-27 21:41:45 +000036
37/**
38 * Python code generator.
39 *
David Reiss0d6eb962008-03-27 21:41:45 +000040 */
41class t_py_generator : public t_generator {
42 public:
43 t_py_generator(
44 t_program* program,
45 const std::map<std::string, std::string>& parsed_options,
46 const std::string& option_string)
47 : t_generator(program)
48 {
Roger Meier3b771a12010-11-17 22:11:26 +000049 (void) option_string;
David Reiss0d6eb962008-03-27 21:41:45 +000050 std::map<std::string, std::string>::const_iterator iter;
51
52 iter = parsed_options.find("new_style");
53 gen_newstyle_ = (iter != parsed_options.end());
54
Roger Meierf4eec7a2011-09-11 18:16:21 +000055 iter = parsed_options.find("slots");
56 gen_slots_ = (iter != parsed_options.end());
57
58 iter = parsed_options.find("dynamic");
59 gen_dynamic_ = (iter != parsed_options.end());
60
61 if (gen_dynamic_) {
62 gen_newstyle_ = 0; // dynamic is newstyle
63 gen_dynbaseclass_ = "TBase";
64 gen_dynbaseclass_exc_ = "TExceptionBase";
65 import_dynbase_ = "from thrift.protocol.TBase import TBase, TExceptionBase\n";
66 }
67
68 iter = parsed_options.find("dynbase");
69 if (iter != parsed_options.end()) {
70 gen_dynbase_ = true;
71 gen_dynbaseclass_ = (iter->second);
72 }
73
74 iter = parsed_options.find("dynexc");
75 if (iter != parsed_options.end()) {
76 gen_dynbaseclass_exc_ = (iter->second);
77 }
78
79 iter = parsed_options.find("dynimport");
80 if (iter != parsed_options.end()) {
81 gen_dynbase_ = true;
82 import_dynbase_ = (iter->second);
83 }
84
Kevin Clark120ff312009-03-03 02:25:50 +000085 iter = parsed_options.find("twisted");
86 gen_twisted_ = (iter != parsed_options.end());
87
David Reiss95c005a2010-07-01 05:36:25 +000088 iter = parsed_options.find("utf8strings");
89 gen_utf8strings_ = (iter != parsed_options.end());
90
Roger Meierf4eec7a2011-09-11 18:16:21 +000091 copy_options_ = option_string;
92
Esteve Fernandez0e8e6092009-09-17 19:19:11 +000093 if (gen_twisted_){
94 out_dir_base_ = "gen-py.twisted";
95 } else {
96 out_dir_base_ = "gen-py";
97 }
David Reiss0d6eb962008-03-27 21:41:45 +000098 }
99
100 /**
101 * Init and close methods
102 */
103
104 void init_generator();
105 void close_generator();
106
107 /**
108 * Program-level generation functions
109 */
110
111 void generate_typedef (t_typedef* ttypedef);
112 void generate_enum (t_enum* tenum);
113 void generate_const (t_const* tconst);
114 void generate_struct (t_struct* tstruct);
115 void generate_xception (t_struct* txception);
116 void generate_service (t_service* tservice);
117
118 std::string render_const_value(t_type* type, t_const_value* value);
119
120 /**
121 * Struct generation code
122 */
123
124 void generate_py_struct(t_struct* tstruct, bool is_exception);
125 void generate_py_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
126 void generate_py_struct_reader(std::ofstream& out, t_struct* tstruct);
127 void generate_py_struct_writer(std::ofstream& out, t_struct* tstruct);
Bryan Duxburyc377c322010-09-02 15:37:19 +0000128 void generate_py_struct_required_validator(std::ofstream& out, t_struct* tstruct);
David Reiss0d6eb962008-03-27 21:41:45 +0000129 void generate_py_function_helpers(t_function* tfunction);
130
131 /**
132 * Service-level generation functions
133 */
134
135 void generate_service_helpers (t_service* tservice);
136 void generate_service_interface (t_service* tservice);
137 void generate_service_client (t_service* tservice);
138 void generate_service_remote (t_service* tservice);
139 void generate_service_server (t_service* tservice);
140 void generate_process_function (t_service* tservice, t_function* tfunction);
141
142 /**
143 * Serialization constructs
144 */
145
146 void generate_deserialize_field (std::ofstream &out,
147 t_field* tfield,
148 std::string prefix="",
149 bool inclass=false);
150
151 void generate_deserialize_struct (std::ofstream &out,
152 t_struct* tstruct,
153 std::string prefix="");
154
155 void generate_deserialize_container (std::ofstream &out,
156 t_type* ttype,
157 std::string prefix="");
158
159 void generate_deserialize_set_element (std::ofstream &out,
160 t_set* tset,
161 std::string prefix="");
162
163 void generate_deserialize_map_element (std::ofstream &out,
164 t_map* tmap,
165 std::string prefix="");
166
167 void generate_deserialize_list_element (std::ofstream &out,
168 t_list* tlist,
169 std::string prefix="");
170
171 void generate_serialize_field (std::ofstream &out,
172 t_field* tfield,
173 std::string prefix="");
174
175 void generate_serialize_struct (std::ofstream &out,
176 t_struct* tstruct,
177 std::string prefix="");
178
179 void generate_serialize_container (std::ofstream &out,
180 t_type* ttype,
181 std::string prefix="");
182
183 void generate_serialize_map_element (std::ofstream &out,
184 t_map* tmap,
185 std::string kiter,
186 std::string viter);
187
188 void generate_serialize_set_element (std::ofstream &out,
189 t_set* tmap,
190 std::string iter);
191
192 void generate_serialize_list_element (std::ofstream &out,
193 t_list* tlist,
194 std::string iter);
195
David Reiss885c82d2009-03-26 08:40:55 +0000196 void generate_python_docstring (std::ofstream& out,
197 t_struct* tstruct);
198
199 void generate_python_docstring (std::ofstream& out,
200 t_function* tfunction);
201
202 void generate_python_docstring (std::ofstream& out,
203 t_doc* tdoc,
204 t_struct* tstruct,
205 const char* subheader);
206
207 void generate_python_docstring (std::ofstream& out,
208 t_doc* tdoc);
209
David Reiss0d6eb962008-03-27 21:41:45 +0000210 /**
211 * Helper rendering functions
212 */
213
214 std::string py_autogen_comment();
215 std::string py_imports();
216 std::string render_includes();
217 std::string render_fastbinary_includes();
David Reiss46bb4ae2009-01-14 22:34:15 +0000218 std::string declare_argument(t_field* tfield);
219 std::string render_field_default_value(t_field* tfield);
David Reiss0d6eb962008-03-27 21:41:45 +0000220 std::string type_name(t_type* ttype);
221 std::string function_signature(t_function* tfunction, std::string prefix="");
Kevin Clark120ff312009-03-03 02:25:50 +0000222 std::string function_signature_if(t_function* tfunction, std::string prefix="");
David Reiss0d6eb962008-03-27 21:41:45 +0000223 std::string argument_list(t_struct* tstruct);
224 std::string type_to_enum(t_type* ttype);
225 std::string type_to_spec_args(t_type* ttype);
226
Bryan Duxburyc39817c2010-08-20 16:45:13 +0000227 static bool is_valid_namespace(const std::string& sub_namespace) {
228 return sub_namespace == "twisted";
229 }
230
231 static std::string get_real_py_module(const t_program* program, bool gen_twisted) {
232 if(gen_twisted) {
233 std::string twisted_module = program->get_namespace("py.twisted");
234 if(!twisted_module.empty()){
235 return twisted_module;
236 }
237 }
238
David Reiss320e45c2008-03-27 21:41:54 +0000239 std::string real_module = program->get_namespace("py");
David Reiss0d6eb962008-03-27 21:41:45 +0000240 if (real_module.empty()) {
241 return program->get_name();
242 }
243 return real_module;
244 }
245
246 private:
247
248 /**
Roger Meierf4eec7a2011-09-11 18:16:21 +0000249 * True if we should generate new-style classes.
David Reiss0d6eb962008-03-27 21:41:45 +0000250 */
251 bool gen_newstyle_;
252
Roger Meierf4eec7a2011-09-11 18:16:21 +0000253 /**
254 * True if we should generate dynamic style classes.
255 */
256 bool gen_dynamic_;
257
258 bool gen_dynbase_;
259 std::string gen_dynbaseclass_;
260 std::string gen_dynbaseclass_exc_;
261
262 std::string import_dynbase_;
263
264 bool gen_slots_;
265
266 std::string copy_options_;
267
David Reiss0d6eb962008-03-27 21:41:45 +0000268 /**
Roger Meierf4eec7a2011-09-11 18:16:21 +0000269 * True if we should generate Twisted-friendly RPC services.
Kevin Clark120ff312009-03-03 02:25:50 +0000270 */
271 bool gen_twisted_;
272
273 /**
Roger Meierf4eec7a2011-09-11 18:16:21 +0000274 * True if strings should be encoded using utf-8.
David Reiss95c005a2010-07-01 05:36:25 +0000275 */
276 bool gen_utf8strings_;
277
278 /**
David Reiss0d6eb962008-03-27 21:41:45 +0000279 * File streams
280 */
281
282 std::ofstream f_types_;
283 std::ofstream f_consts_;
284 std::ofstream f_service_;
285
286 std::string package_dir_;
287
288};
289
290
Mark Sleee50b3092006-09-04 00:06:47 +0000291/**
292 * Prepares for file generation by opening up the necessary file output
293 * streams.
294 *
295 * @param tprogram The program to generate
296 */
Mark Sleef0712dc2006-10-25 19:03:57 +0000297void t_py_generator::init_generator() {
Mark Sleee50b3092006-09-04 00:06:47 +0000298 // Make output directory
Bryan Duxburyc39817c2010-08-20 16:45:13 +0000299 string module = get_real_py_module(program_, gen_twisted_);
dweatherford65b70752007-10-31 02:18:14 +0000300 package_dir_ = get_out_dir();
David Reissc6fc3292007-08-30 00:58:43 +0000301 while (true) {
302 // TODO: Do better error checking here.
David Reiss204420f2008-01-11 20:59:03 +0000303 MKDIR(package_dir_.c_str());
David Reissc6fc3292007-08-30 00:58:43 +0000304 std::ofstream init_py((package_dir_+"/__init__.py").c_str());
305 init_py.close();
306 if (module.empty()) {
307 break;
308 }
309 string::size_type pos = module.find('.');
310 if (pos == string::npos) {
311 package_dir_ += "/";
312 package_dir_ += module;
313 module.clear();
314 } else {
315 package_dir_ += "/";
316 package_dir_ += module.substr(0, pos);
317 module.erase(0, pos+1);
318 }
319 }
Mark Sleee50b3092006-09-04 00:06:47 +0000320
321 // Make output file
Mark Sleeecf490e2007-02-21 00:05:18 +0000322 string f_types_name = package_dir_+"/"+"ttypes.py";
Mark Sleee50b3092006-09-04 00:06:47 +0000323 f_types_.open(f_types_name.c_str());
324
Mark Sleeecf490e2007-02-21 00:05:18 +0000325 string f_consts_name = package_dir_+"/"+"constants.py";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000326 f_consts_.open(f_consts_name.c_str());
327
Mark Sleeecf490e2007-02-21 00:05:18 +0000328 string f_init_name = package_dir_+"/__init__.py";
329 ofstream f_init;
330 f_init.open(f_init_name.c_str());
331 f_init <<
332 "__all__ = ['ttypes', 'constants'";
333 vector<t_service*> services = program_->get_services();
334 vector<t_service*>::iterator sv_iter;
335 for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
336 f_init << ", '" << (*sv_iter)->get_name() << "'";
337 }
338 f_init << "]" << endl;
339 f_init.close();
340
Mark Sleee50b3092006-09-04 00:06:47 +0000341 // Print header
342 f_types_ <<
343 py_autogen_comment() << endl <<
344 py_imports() << endl <<
David Reiss382fc302007-08-25 18:01:30 +0000345 render_includes() << endl <<
David Reiss5db3e922007-08-30 23:07:45 +0000346 render_fastbinary_includes() <<
347 endl << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000348
349 f_consts_ <<
350 py_autogen_comment() << endl <<
351 py_imports() << endl <<
Mark Sleeecf490e2007-02-21 00:05:18 +0000352 "from ttypes import *" << endl <<
Mark Sleeaa7671d2006-11-29 03:19:31 +0000353 endl;
Mark Sleef0712dc2006-10-25 19:03:57 +0000354}
355
356/**
357 * Renders all the imports necessary for including another Thrift program
358 */
359string t_py_generator::render_includes() {
360 const vector<t_program*>& includes = program_->get_includes();
361 string result = "";
362 for (size_t i = 0; i < includes.size(); ++i) {
Bryan Duxburyc39817c2010-08-20 16:45:13 +0000363 result += "import " + get_real_py_module(includes[i], gen_twisted_) + ".ttypes\n";
Mark Sleef0712dc2006-10-25 19:03:57 +0000364 }
365 if (includes.size() > 0) {
366 result += "\n";
367 }
368 return result;
Mark Sleee50b3092006-09-04 00:06:47 +0000369}
370
371/**
David Reiss5db3e922007-08-30 23:07:45 +0000372 * Renders all the imports necessary to use the accelerated TBinaryProtocol
373 */
374string t_py_generator::render_fastbinary_includes() {
Roger Meierf4eec7a2011-09-11 18:16:21 +0000375 string hdr = "";
376 if (gen_dynamic_) {
377 hdr += std::string(import_dynbase_);
378 } else {
379 hdr +=
380 "from thrift.transport import TTransport\n"
381 "from thrift.protocol import TBinaryProtocol, TProtocol\n"
382 "try:\n"
383 " from thrift.protocol import fastbinary\n"
384 "except:\n"
385 " fastbinary = None\n";
386 }
387 return hdr;
David Reiss5db3e922007-08-30 23:07:45 +0000388}
389
390/**
Mark Sleee50b3092006-09-04 00:06:47 +0000391 * Autogen'd comment
392 */
393string t_py_generator::py_autogen_comment() {
394 return
395 std::string("#\n") +
Roger Meier08d46812011-04-12 19:08:21 +0000396 "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
Mark Sleee50b3092006-09-04 00:06:47 +0000397 "#\n" +
398 "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
Roger Meierf4eec7a2011-09-11 18:16:21 +0000399 "#\n" +
400 "# options string: " + copy_options_ + "\n" +
Mark Sleee50b3092006-09-04 00:06:47 +0000401 "#\n";
402}
403
404/**
Mark Sleef5377b32006-10-10 01:42:59 +0000405 * Prints standard thrift imports
Mark Sleee50b3092006-09-04 00:06:47 +0000406 */
407string t_py_generator::py_imports() {
408 return
Jake Farrell2361dd12011-10-07 17:41:48 +0000409 string("from thrift.Thrift import TType, TMessageType, TException");
Mark Sleee50b3092006-09-04 00:06:47 +0000410}
411
412/**
Mark Sleef5377b32006-10-10 01:42:59 +0000413 * Closes the type files
Mark Sleee50b3092006-09-04 00:06:47 +0000414 */
Mark Sleef0712dc2006-10-25 19:03:57 +0000415void t_py_generator::close_generator() {
Mark Sleee50b3092006-09-04 00:06:47 +0000416 // Close types file
417 f_types_.close();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000418 f_consts_.close();
Mark Sleee50b3092006-09-04 00:06:47 +0000419}
420
421/**
422 * Generates a typedef. This is not done in Python, types are all implicit.
423 *
424 * @param ttypedef The type definition
425 */
Roger Meier3b771a12010-11-17 22:11:26 +0000426void t_py_generator::generate_typedef(t_typedef* ttypedef) {
427 (void) ttypedef;
428}
Mark Sleee50b3092006-09-04 00:06:47 +0000429
430/**
Mark Sleef5377b32006-10-10 01:42:59 +0000431 * Generates code for an enumerated type. Done using a class to scope
432 * the values.
Mark Sleee50b3092006-09-04 00:06:47 +0000433 *
434 * @param tenum The enumeration
435 */
436void t_py_generator::generate_enum(t_enum* tenum) {
David Reiss8266e012009-10-21 06:09:16 +0000437 std::ostringstream to_string_mapping, from_string_mapping;
438
Mark Sleee50b3092006-09-04 00:06:47 +0000439 f_types_ <<
David Reiss6495adb2007-12-18 03:37:30 +0000440 "class " << tenum->get_name() <<
441 (gen_newstyle_ ? "(object)" : "") <<
Roger Meierf4eec7a2011-09-11 18:16:21 +0000442 (gen_dynamic_ ? "(" + gen_dynbaseclass_ + ")" : "") <<
David Reiss6495adb2007-12-18 03:37:30 +0000443 ":" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000444 indent_up();
David Reiss885c82d2009-03-26 08:40:55 +0000445 generate_python_docstring(f_types_, tenum);
David Reiss382fc302007-08-25 18:01:30 +0000446
David Reiss8266e012009-10-21 06:09:16 +0000447 to_string_mapping << indent() << "_VALUES_TO_NAMES = {" << endl;
448 from_string_mapping << indent() << "_NAMES_TO_VALUES = {" << endl;
449
Mark Slee30152872006-11-28 01:24:07 +0000450 vector<t_enum_value*> constants = tenum->get_constants();
451 vector<t_enum_value*>::iterator c_iter;
Mark Sleee50b3092006-09-04 00:06:47 +0000452 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
Bryan Duxburya406b902010-09-27 23:37:44 +0000453 int value = (*c_iter)->get_value();
454 indent(f_types_) << (*c_iter)->get_name() << " = " << value << endl;
David Reiss8266e012009-10-21 06:09:16 +0000455
456 // Dictionaries to/from string names of enums
457 to_string_mapping <<
458 indent() << indent() << value << ": \"" <<
459 escape_string((*c_iter)->get_name()) << "\"," << endl;
460 from_string_mapping <<
461 indent() << indent() << '"' << escape_string((*c_iter)->get_name()) <<
462 "\": " << value << ',' << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000463 }
David Reiss8266e012009-10-21 06:09:16 +0000464 to_string_mapping << indent() << "}" << endl;
465 from_string_mapping << indent() << "}" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000466
467 indent_down();
468 f_types_ << endl;
David Reiss8266e012009-10-21 06:09:16 +0000469 f_types_ << to_string_mapping.str() << endl << from_string_mapping.str() << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000470}
471
Mark Sleef5377b32006-10-10 01:42:59 +0000472/**
Mark Sleeaa7671d2006-11-29 03:19:31 +0000473 * Generate a constant value
474 */
475void t_py_generator::generate_const(t_const* tconst) {
476 t_type* type = tconst->get_type();
477 string name = tconst->get_name();
478 t_const_value* value = tconst->get_value();
David Reiss382fc302007-08-25 18:01:30 +0000479
Mark Slee7ff32452007-02-01 05:26:18 +0000480 indent(f_consts_) << name << " = " << render_const_value(type, value);
Bryan Duxbury1316ed92010-09-02 14:20:01 +0000481 f_consts_ << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000482}
483
484/**
485 * Prints the value of a constant with the given type. Note that type checking
486 * is NOT performed in this function as it is always run beforehand using the
487 * validate_types method in main.cc
488 */
Mark Slee7ff32452007-02-01 05:26:18 +0000489string t_py_generator::render_const_value(t_type* type, t_const_value* value) {
David Reiss9a4edfa2008-05-01 05:52:50 +0000490 type = get_true_type(type);
Mark Slee7ff32452007-02-01 05:26:18 +0000491 std::ostringstream out;
492
Mark Sleeaa7671d2006-11-29 03:19:31 +0000493 if (type->is_base_type()) {
494 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
495 switch (tbase) {
496 case t_base_type::TYPE_STRING:
David Reiss82e6fc02009-03-26 23:32:36 +0000497 out << '"' << get_escaped_string(value) << '"';
Mark Sleeaa7671d2006-11-29 03:19:31 +0000498 break;
499 case t_base_type::TYPE_BOOL:
Mark Slee7ff32452007-02-01 05:26:18 +0000500 out << (value->get_integer() > 0 ? "True" : "False");
Mark Sleeaa7671d2006-11-29 03:19:31 +0000501 break;
502 case t_base_type::TYPE_BYTE:
503 case t_base_type::TYPE_I16:
504 case t_base_type::TYPE_I32:
505 case t_base_type::TYPE_I64:
Mark Slee7ff32452007-02-01 05:26:18 +0000506 out << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000507 break;
508 case t_base_type::TYPE_DOUBLE:
509 if (value->get_type() == t_const_value::CV_INTEGER) {
Mark Slee7ff32452007-02-01 05:26:18 +0000510 out << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000511 } else {
Mark Slee7ff32452007-02-01 05:26:18 +0000512 out << value->get_double();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000513 }
514 break;
515 default:
David Reissdd7796f2007-08-28 21:09:06 +0000516 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
Mark Sleeaa7671d2006-11-29 03:19:31 +0000517 }
518 } else if (type->is_enum()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000519 indent(out) << value->get_integer();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000520 } else if (type->is_struct() || type->is_xception()) {
David Reiss46bb4ae2009-01-14 22:34:15 +0000521 out << type->get_name() << "(**{" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000522 indent_up();
523 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
524 vector<t_field*>::const_iterator f_iter;
525 const map<t_const_value*, t_const_value*>& val = value->get_map();
526 map<t_const_value*, t_const_value*>::const_iterator v_iter;
527 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
528 t_type* field_type = NULL;
529 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
530 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
531 field_type = (*f_iter)->get_type();
532 }
533 }
534 if (field_type == NULL) {
535 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
536 }
Mark Slee7ff32452007-02-01 05:26:18 +0000537 out << indent();
538 out << render_const_value(g_type_string, v_iter->first);
539 out << " : ";
540 out << render_const_value(field_type, v_iter->second);
541 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000542 }
543 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000544 indent(out) << "})";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000545 } else if (type->is_map()) {
546 t_type* ktype = ((t_map*)type)->get_key_type();
547 t_type* vtype = ((t_map*)type)->get_val_type();
Mark Slee7ff32452007-02-01 05:26:18 +0000548 out << "{" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000549 indent_up();
550 const map<t_const_value*, t_const_value*>& val = value->get_map();
551 map<t_const_value*, t_const_value*>::const_iterator v_iter;
552 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000553 out << indent();
554 out << render_const_value(ktype, v_iter->first);
555 out << " : ";
556 out << render_const_value(vtype, v_iter->second);
557 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000558 }
559 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000560 indent(out) << "}";
Mark Sleeaa7671d2006-11-29 03:19:31 +0000561 } else if (type->is_list() || type->is_set()) {
562 t_type* etype;
563 if (type->is_list()) {
564 etype = ((t_list*)type)->get_elem_type();
565 } else {
566 etype = ((t_set*)type)->get_elem_type();
567 }
Mark Slee600cdb32006-11-29 22:06:42 +0000568 if (type->is_set()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000569 out << "set(";
Mark Slee600cdb32006-11-29 22:06:42 +0000570 }
Mark Slee7ff32452007-02-01 05:26:18 +0000571 out << "[" << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000572 indent_up();
573 const vector<t_const_value*>& val = value->get_list();
574 vector<t_const_value*>::const_iterator v_iter;
575 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000576 out << indent();
577 out << render_const_value(etype, *v_iter);
578 out << "," << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000579 }
580 indent_down();
Mark Slee7ff32452007-02-01 05:26:18 +0000581 indent(out) << "]";
Mark Slee600cdb32006-11-29 22:06:42 +0000582 if (type->is_set()) {
Mark Slee7ff32452007-02-01 05:26:18 +0000583 out << ")";
Mark Slee600cdb32006-11-29 22:06:42 +0000584 }
David Reiss9a4edfa2008-05-01 05:52:50 +0000585 } else {
586 throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000587 }
Mark Slee7ff32452007-02-01 05:26:18 +0000588
589 return out.str();
Mark Sleeaa7671d2006-11-29 03:19:31 +0000590}
591
592/**
Mark Sleef5377b32006-10-10 01:42:59 +0000593 * Generates a python struct
594 */
Mark Sleee50b3092006-09-04 00:06:47 +0000595void t_py_generator::generate_struct(t_struct* tstruct) {
596 generate_py_struct(tstruct, false);
597}
598
599/**
600 * Generates a struct definition for a thrift exception. Basically the same
601 * as a struct but extends the Exception class.
602 *
603 * @param txception The struct definition
604 */
605void t_py_generator::generate_xception(t_struct* txception) {
David Reiss382fc302007-08-25 18:01:30 +0000606 generate_py_struct(txception, true);
Mark Sleee50b3092006-09-04 00:06:47 +0000607}
608
Mark Sleef5377b32006-10-10 01:42:59 +0000609/**
610 * Generates a python struct
611 */
Mark Sleee50b3092006-09-04 00:06:47 +0000612void t_py_generator::generate_py_struct(t_struct* tstruct,
613 bool is_exception) {
614 generate_py_struct_definition(f_types_, tstruct, is_exception);
615}
616
617/**
David Reiss6495adb2007-12-18 03:37:30 +0000618 * Generates a struct definition for a thrift data type.
Mark Sleee50b3092006-09-04 00:06:47 +0000619 *
620 * @param tstruct The struct definition
621 */
622void t_py_generator::generate_py_struct_definition(ofstream& out,
623 t_struct* tstruct,
624 bool is_exception,
625 bool is_result) {
Roger Meier3b771a12010-11-17 22:11:26 +0000626 (void) is_result;
Mark Sleee50b3092006-09-04 00:06:47 +0000627 const vector<t_field*>& members = tstruct->get_members();
David Reiss1cc89952009-04-27 19:36:50 +0000628 const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
David Reiss382fc302007-08-25 18:01:30 +0000629 vector<t_field*>::const_iterator m_iter;
Mark Sleee50b3092006-09-04 00:06:47 +0000630
Bryan Duxbury1316ed92010-09-02 14:20:01 +0000631 out << std::endl <<
Mark Sleee50b3092006-09-04 00:06:47 +0000632 "class " << tstruct->get_name();
633 if (is_exception) {
Roger Meierf4eec7a2011-09-11 18:16:21 +0000634 if (gen_dynamic_) {
635 out << "(" << gen_dynbaseclass_exc_ << ")";
636 } else {
Jake Farrell2ce7f662011-10-07 00:04:56 +0000637 out << "(TException)";
Roger Meierf4eec7a2011-09-11 18:16:21 +0000638 }
639 } else {
640 if (gen_newstyle_) {
641 out << "(object)";
642 } else if (gen_dynamic_) {
643 out << "(" << gen_dynbaseclass_ << ")";
644 }
Mark Sleee50b3092006-09-04 00:06:47 +0000645 }
Roger Meierf4eec7a2011-09-11 18:16:21 +0000646 out << ":" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000647 indent_up();
David Reiss885c82d2009-03-26 08:40:55 +0000648 generate_python_docstring(out, tstruct);
Mark Sleee50b3092006-09-04 00:06:47 +0000649
650 out << endl;
651
David Reiss382fc302007-08-25 18:01:30 +0000652 /*
653 Here we generate the structure specification for the fastbinary codec.
654 These specifications have the following structure:
655 thrift_spec -> tuple of item_spec
656 item_spec -> None | (tag, type_enum, name, spec_args, default)
657 tag -> integer
658 type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
659 name -> string_literal
660 default -> None # Handled by __init__
661 spec_args -> None # For simple types
662 | (type_enum, spec_args) # Value type for list/set
663 | (type_enum, spec_args, type_enum, spec_args)
664 # Key and value for map
665 | (class_name, spec_args_ptr) # For struct/exception
666 class_name -> identifier # Basically a pointer to the class
667 spec_args_ptr -> expression # just class_name.spec_args
668
669 TODO(dreiss): Consider making this work for structs with negative tags.
670 */
671
Roger Meierf4eec7a2011-09-11 18:16:21 +0000672 if (gen_slots_) {
673 indent(out) << "__slots__ = [ " << endl;
674 indent_up();
675 for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
676 indent(out) << "'" << (*m_iter)->get_name() << "'," << endl;
677 }
678 indent_down();
679 indent(out) << " ]" << endl << endl;
680
681 }
682
David Reiss5db3e922007-08-30 23:07:45 +0000683 // TODO(dreiss): Look into generating an empty tuple instead of None
684 // for structures with no members.
685 // TODO(dreiss): Test encoding of structs where some inner structs
686 // don't have thrift_spec.
David Reiss1cc89952009-04-27 19:36:50 +0000687 if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
David Reiss382fc302007-08-25 18:01:30 +0000688 indent(out) << "thrift_spec = (" << endl;
689 indent_up();
690
691 int sorted_keys_pos = 0;
David Reiss1cc89952009-04-27 19:36:50 +0000692 for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
David Reiss382fc302007-08-25 18:01:30 +0000693
694 for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
695 indent(out) << "None, # " << sorted_keys_pos << endl;
696 }
697
698 indent(out) << "(" << (*m_iter)->get_key() << ", "
699 << type_to_enum((*m_iter)->get_type()) << ", "
700 << "'" << (*m_iter)->get_name() << "'" << ", "
701 << type_to_spec_args((*m_iter)->get_type()) << ", "
David Reiss46bb4ae2009-01-14 22:34:15 +0000702 << render_field_default_value(*m_iter) << ", "
David Reiss382fc302007-08-25 18:01:30 +0000703 << "),"
704 << " # " << sorted_keys_pos
705 << endl;
706
707 sorted_keys_pos ++;
708 }
709
710 indent_down();
711 indent(out) << ")" << endl << endl;
David Reiss5db3e922007-08-30 23:07:45 +0000712 } else {
713 indent(out) << "thrift_spec = None" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000714 }
715
David Reiss5db3e922007-08-30 23:07:45 +0000716
David Reiss46bb4ae2009-01-14 22:34:15 +0000717 if (members.size() > 0) {
718 out <<
719 indent() << "def __init__(self,";
Mark Sleee50b3092006-09-04 00:06:47 +0000720
Mark Sleee50b3092006-09-04 00:06:47 +0000721 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
Mark Slee7ff32452007-02-01 05:26:18 +0000722 // This fills in default values, as opposed to nulls
David Reiss46bb4ae2009-01-14 22:34:15 +0000723 out << " " << declare_argument(*m_iter) << ",";
Mark Sleee50b3092006-09-04 00:06:47 +0000724 }
Mark Sleeaa7671d2006-11-29 03:19:31 +0000725
David Reiss46bb4ae2009-01-14 22:34:15 +0000726 out << "):" << endl;
727
Mark Sleeaa7671d2006-11-29 03:19:31 +0000728 indent_up();
David Reiss46bb4ae2009-01-14 22:34:15 +0000729
Mark Sleeaa7671d2006-11-29 03:19:31 +0000730 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
David Reiss46bb4ae2009-01-14 22:34:15 +0000731 // Initialize fields
732 t_type* type = (*m_iter)->get_type();
733 if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != NULL) {
734 indent(out) <<
735 "if " << (*m_iter)->get_name() << " is " << "self.thrift_spec[" <<
736 (*m_iter)->get_key() << "][4]:" << endl;
737 indent(out) << " " << (*m_iter)->get_name() << " = " <<
738 render_field_default_value(*m_iter) << endl;
739 }
740 indent(out) <<
741 "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl;
Mark Sleeaa7671d2006-11-29 03:19:31 +0000742 }
David Reiss46bb4ae2009-01-14 22:34:15 +0000743
Mark Sleeaa7671d2006-11-29 03:19:31 +0000744 indent_down();
David Reiss46bb4ae2009-01-14 22:34:15 +0000745
746 out << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000747 }
748
Roger Meierf4eec7a2011-09-11 18:16:21 +0000749 if (!gen_dynamic_) {
750 generate_py_struct_reader(out, tstruct);
751 generate_py_struct_writer(out, tstruct);
752 }
Mark Sleee50b3092006-09-04 00:06:47 +0000753
David Reiss4f319202009-04-29 23:35:01 +0000754 // For exceptions only, generate a __str__ method. This is
755 // because when raised exceptions are printed to the console, __repr__
756 // isn't used. See python bug #5882
757 if (is_exception) {
758 out <<
759 indent() << "def __str__(self):" << endl <<
760 indent() << " return repr(self)" << endl <<
761 endl;
762 }
763
Roger Meierf4eec7a2011-09-11 18:16:21 +0000764 if (!gen_slots_) {
765 // Printing utilities so that on the command line thrift
766 // structs look pretty like dictionaries
767 out <<
768 indent() << "def __repr__(self):" << endl <<
769 indent() << " L = ['%s=%r' % (key, value)" << endl <<
770 indent() << " for key, value in self.__dict__.iteritems()]" << endl <<
771 indent() << " return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl <<
772 endl;
Mark Slee748e5762006-10-04 21:51:05 +0000773
Roger Meierf4eec7a2011-09-11 18:16:21 +0000774 // Equality and inequality methods that compare by value
775 out <<
776 indent() << "def __eq__(self, other):" << endl;
777 indent_up();
778 out <<
779 indent() << "return isinstance(other, self.__class__) and "
780 "self.__dict__ == other.__dict__" << endl;
781 indent_down();
782 out << endl;
David Reiss382fc302007-08-25 18:01:30 +0000783
Roger Meierf4eec7a2011-09-11 18:16:21 +0000784 out <<
785 indent() << "def __ne__(self, other):" << endl;
786 indent_up();
787
788 out <<
789 indent() << "return not (self == other)" << endl;
790 indent_down();
791 } else if (!gen_dynamic_) {
792 // no base class available to implement __eq__ and __repr__ and __ne__ for us
793 // so we must provide one that uses __slots__
794 out <<
795 indent() << "def __repr__(self):" << endl <<
796 indent() << " L = ['%s=%r' % (key, getattr(self, key))" << endl <<
797 indent() << " for key in self.__slots__]" << endl <<
798 indent() << " return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl <<
799 endl;
800
801 // Equality method that compares each attribute by value and type, walking __slots__
802 out <<
803 indent() << "def __eq__(self, other):" << endl <<
804 indent() << " if not isinstance(other, self.__class__):" << endl <<
805 indent() << " return False" << endl <<
806 indent() << " for attr in self.__slots__:" << endl <<
807 indent() << " my_val = getattr(self, attr)" << endl <<
808 indent() << " other_val = getattr(other, attr)" << endl <<
809 indent() << " if my_val != other_val:" << endl <<
810 indent() << " return False" << endl <<
811 indent() << " return True" << endl <<
812 endl;
813
814 out <<
815 indent() << "def __ne__(self, other):" << endl <<
816 indent() << " return not (self == other)" << endl <<
817 endl;
818 }
Mark Sleee50b3092006-09-04 00:06:47 +0000819 indent_down();
820}
821
Mark Sleef5377b32006-10-10 01:42:59 +0000822/**
823 * Generates the read method for a struct
824 */
Mark Sleee50b3092006-09-04 00:06:47 +0000825void t_py_generator::generate_py_struct_reader(ofstream& out,
826 t_struct* tstruct) {
827 const vector<t_field*>& fields = tstruct->get_members();
828 vector<t_field*>::const_iterator f_iter;
829
830 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000831 "def read(self, iprot):" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000832 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000833
Mark Sleee50b3092006-09-04 00:06:47 +0000834 indent(out) <<
David Reiss382fc302007-08-25 18:01:30 +0000835 "if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
David Reiss5db3e922007-08-30 23:07:45 +0000836 "and isinstance(iprot.trans, TTransport.CReadableTransport) "
837 "and self.thrift_spec is not None "
838 "and fastbinary is not None:" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000839 indent_up();
840
841 indent(out) <<
842 "fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))" << endl;
843 indent(out) <<
844 "return" << endl;
845 indent_down();
846
847 indent(out) <<
848 "iprot.readStructBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000849
850 // Loop over reading in fields
851 indent(out) <<
852 "while True:" << endl;
853 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000854
Mark Sleee50b3092006-09-04 00:06:47 +0000855 // Read beginning field marker
856 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000857 "(fname, ftype, fid) = iprot.readFieldBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000858
859 // Check for field STOP marker and break
860 indent(out) <<
861 "if ftype == TType.STOP:" << endl;
862 indent_up();
863 indent(out) <<
864 "break" << endl;
865 indent_down();
David Reiss382fc302007-08-25 18:01:30 +0000866
Mark Sleee50b3092006-09-04 00:06:47 +0000867 // Switch statement on the field we are reading
868 bool first = true;
David Reiss382fc302007-08-25 18:01:30 +0000869
Mark Sleee50b3092006-09-04 00:06:47 +0000870 // Generate deserialization code for known cases
871 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
872 if (first) {
873 first = false;
874 out <<
875 indent() << "if ";
876 } else {
877 out <<
878 indent() << "elif ";
879 }
880 out << "fid == " << (*f_iter)->get_key() << ":" << endl;
881 indent_up();
Mark Slee2006d992007-01-29 17:58:54 +0000882 indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl;
883 indent_up();
Mark Sleee50b3092006-09-04 00:06:47 +0000884 generate_deserialize_field(out, *f_iter, "self.");
885 indent_down();
Mark Slee2006d992007-01-29 17:58:54 +0000886 out <<
887 indent() << "else:" << endl <<
888 indent() << " iprot.skip(ftype)" << endl;
889 indent_down();
Mark Sleee50b3092006-09-04 00:06:47 +0000890 }
David Reiss382fc302007-08-25 18:01:30 +0000891
Mark Sleee50b3092006-09-04 00:06:47 +0000892 // In the default case we skip the field
893 out <<
894 indent() << "else:" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +0000895 indent() << " iprot.skip(ftype)" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000896
Mark Sleee50b3092006-09-04 00:06:47 +0000897 // Read field end marker
898 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000899 "iprot.readFieldEnd()" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000900
Mark Sleee50b3092006-09-04 00:06:47 +0000901 indent_down();
David Reiss382fc302007-08-25 18:01:30 +0000902
Mark Sleee50b3092006-09-04 00:06:47 +0000903 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000904 "iprot.readStructEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000905
906 indent_down();
907 out << endl;
908}
909
910void t_py_generator::generate_py_struct_writer(ofstream& out,
911 t_struct* tstruct) {
912 string name = tstruct->get_name();
Bryan Duxburyff219ac2009-04-10 21:51:00 +0000913 const vector<t_field*>& fields = tstruct->get_sorted_members();
Mark Sleee50b3092006-09-04 00:06:47 +0000914 vector<t_field*>::const_iterator f_iter;
915
916 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000917 "def write(self, oprot):" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000918 indent_up();
David Reiss382fc302007-08-25 18:01:30 +0000919
920 indent(out) <<
David Reiss5db3e922007-08-30 23:07:45 +0000921 "if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
922 "and self.thrift_spec is not None "
923 "and fastbinary is not None:" << endl;
David Reiss382fc302007-08-25 18:01:30 +0000924 indent_up();
925
926 indent(out) <<
927 "oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))" << endl;
928 indent(out) <<
929 "return" << endl;
930 indent_down();
931
Mark Sleee50b3092006-09-04 00:06:47 +0000932 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000933 "oprot.writeStructBegin('" << name << "')" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000934
935 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
936 // Write field header
937 indent(out) <<
Bryan Duxbury1709d402011-03-23 18:15:19 +0000938 "if self." << (*f_iter)->get_name() << " is not None:" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000939 indent_up();
940 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000941 "oprot.writeFieldBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +0000942 "'" << (*f_iter)->get_name() << "', " <<
943 type_to_enum((*f_iter)->get_type()) << ", " <<
944 (*f_iter)->get_key() << ")" << endl;
945
946 // Write field contents
947 generate_serialize_field(out, *f_iter, "self.");
948
949 // Write field closer
950 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +0000951 "oprot.writeFieldEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000952
953 indent_down();
954 }
955
956 // Write the struct map
957 out <<
Mark Slee5946a182006-10-25 21:38:39 +0000958 indent() << "oprot.writeFieldStop()" << endl <<
959 indent() << "oprot.writeStructEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +0000960
Bryan Duxburyc9929302011-03-15 17:10:15 +0000961 out << endl;
Bryan Duxburyc377c322010-09-02 15:37:19 +0000962
Mark Sleee50b3092006-09-04 00:06:47 +0000963 indent_down();
Bryan Duxburyc9929302011-03-15 17:10:15 +0000964 generate_py_struct_required_validator(out, tstruct);
Mark Sleee50b3092006-09-04 00:06:47 +0000965 out <<
966 endl;
967}
968
Bryan Duxburyc377c322010-09-02 15:37:19 +0000969void t_py_generator::generate_py_struct_required_validator(ofstream& out,
970 t_struct* tstruct) {
971 indent(out) << "def validate(self):" << endl;
972 indent_up();
973
974 const vector<t_field*>& fields = tstruct->get_members();
975
976 if (fields.size() > 0) {
977 vector<t_field*>::const_iterator f_iter;
978
979 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
980 t_field* field = (*f_iter);
981 if (field->get_req() == t_field::T_REQUIRED) {
982 indent(out) << "if self." << field->get_name() << " is None:" << endl;
983 indent(out) << " raise TProtocol.TProtocolException(message='Required field " <<
984 field->get_name() << " is unset!')" << endl;
985 }
986 }
987 }
988
989 indent(out) << "return" << endl << endl;
990 indent_down();
991}
992
Mark Sleee50b3092006-09-04 00:06:47 +0000993/**
994 * Generates a thrift service.
995 *
996 * @param tservice The service definition
997 */
998void t_py_generator::generate_service(t_service* tservice) {
Mark Sleeecf490e2007-02-21 00:05:18 +0000999 string f_service_name = package_dir_+"/"+service_name_+".py";
Mark Sleee50b3092006-09-04 00:06:47 +00001000 f_service_.open(f_service_name.c_str());
1001
1002 f_service_ <<
1003 py_autogen_comment() << endl <<
1004 py_imports() << endl;
1005
Mark Sleef0712dc2006-10-25 19:03:57 +00001006 if (tservice->get_extends() != NULL) {
1007 f_service_ <<
Bryan Duxburyc39817c2010-08-20 16:45:13 +00001008 "import " << get_real_py_module(tservice->get_extends()->get_program(), gen_twisted_) <<
David Reissc6fc3292007-08-30 00:58:43 +00001009 "." << tservice->get_extends()->get_name() << endl;
Mark Sleef0712dc2006-10-25 19:03:57 +00001010 }
1011
Mark Sleee50b3092006-09-04 00:06:47 +00001012 f_service_ <<
David Reiss382fc302007-08-25 18:01:30 +00001013 "from ttypes import *" << endl <<
Mark Sleec9676562006-09-05 17:34:52 +00001014 "from thrift.Thrift import TProcessor" << endl <<
Kevin Clark120ff312009-03-03 02:25:50 +00001015 render_fastbinary_includes() << endl;
1016
1017 if (gen_twisted_) {
1018 f_service_ <<
1019 "from zope.interface import Interface, implements" << endl <<
1020 "from twisted.internet import defer" << endl <<
1021 "from thrift.transport import TTwisted" << endl;
1022 }
1023
1024 f_service_ << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001025
1026 // Generate the three main parts of the service (well, two for now in PHP)
1027 generate_service_interface(tservice);
1028 generate_service_client(tservice);
Mark Sleec9676562006-09-05 17:34:52 +00001029 generate_service_server(tservice);
Mark Sleef0712dc2006-10-25 19:03:57 +00001030 generate_service_helpers(tservice);
Mark Slee748e5762006-10-04 21:51:05 +00001031 generate_service_remote(tservice);
1032
Mark Sleee50b3092006-09-04 00:06:47 +00001033 // Close service file
Mark Sleee50b3092006-09-04 00:06:47 +00001034 f_service_.close();
1035}
1036
1037/**
1038 * Generates helper functions for a service.
1039 *
1040 * @param tservice The service to generate a header definition for
1041 */
1042void t_py_generator::generate_service_helpers(t_service* tservice) {
1043 vector<t_function*> functions = tservice->get_functions();
1044 vector<t_function*>::iterator f_iter;
1045
1046 f_service_ <<
Bryan Duxbury1316ed92010-09-02 14:20:01 +00001047 "# HELPER FUNCTIONS AND STRUCTURES" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001048
1049 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1050 t_struct* ts = (*f_iter)->get_arglist();
1051 generate_py_struct_definition(f_service_, ts, false);
1052 generate_py_function_helpers(*f_iter);
1053 }
1054}
1055
1056/**
1057 * Generates a struct and helpers for a function.
1058 *
1059 * @param tfunction The function
1060 */
1061void t_py_generator::generate_py_function_helpers(t_function* tfunction) {
David Reiss47329252009-03-24 20:01:02 +00001062 if (!tfunction->is_oneway()) {
David Reiss4704d432009-02-01 00:42:10 +00001063 t_struct result(program_, tfunction->get_name() + "_result");
1064 t_field success(tfunction->get_returntype(), "success", 0);
1065 if (!tfunction->get_returntype()->is_void()) {
1066 result.append(&success);
1067 }
Mark Sleee50b3092006-09-04 00:06:47 +00001068
David Reiss4704d432009-02-01 00:42:10 +00001069 t_struct* xs = tfunction->get_xceptions();
1070 const vector<t_field*>& fields = xs->get_members();
1071 vector<t_field*>::const_iterator f_iter;
1072 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1073 result.append(*f_iter);
1074 }
1075 generate_py_struct_definition(f_service_, &result, false, true);
Mark Sleee50b3092006-09-04 00:06:47 +00001076 }
Mark Sleee50b3092006-09-04 00:06:47 +00001077}
1078
1079/**
1080 * Generates a service interface definition.
1081 *
1082 * @param tservice The service to generate a header definition for
1083 */
1084void t_py_generator::generate_service_interface(t_service* tservice) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001085 string extends = "";
1086 string extends_if = "";
1087 if (tservice->get_extends() != NULL) {
1088 extends = type_name(tservice->get_extends());
1089 extends_if = "(" + extends + ".Iface)";
Kevin Clark120ff312009-03-03 02:25:50 +00001090 } else {
1091 if (gen_twisted_) {
1092 extends_if = "(Interface)";
Roger Meierf4eec7a2011-09-11 18:16:21 +00001093 } else if (gen_newstyle_ || gen_dynamic_) {
David Reissa0bf2c12009-09-16 16:50:00 +00001094 extends_if = "(object)";
Kevin Clark120ff312009-03-03 02:25:50 +00001095 }
Mark Sleef0712dc2006-10-25 19:03:57 +00001096 }
1097
Mark Sleee50b3092006-09-04 00:06:47 +00001098 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001099 "class Iface" << extends_if << ":" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001100 indent_up();
David Reiss885c82d2009-03-26 08:40:55 +00001101 generate_python_docstring(f_service_, tservice);
Mark Sleee50b3092006-09-04 00:06:47 +00001102 vector<t_function*> functions = tservice->get_functions();
David Reiss8cee47c2009-02-07 02:37:05 +00001103 if (functions.empty()) {
1104 f_service_ <<
1105 indent() << "pass" << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001106 } else {
1107 vector<t_function*>::iterator f_iter;
1108 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1109 f_service_ <<
David Reiss885c82d2009-03-26 08:40:55 +00001110 indent() << "def " << function_signature_if(*f_iter) << ":" << endl;
David Reiss64f87522009-03-30 19:31:36 +00001111 indent_up();
David Reiss885c82d2009-03-26 08:40:55 +00001112 generate_python_docstring(f_service_, (*f_iter));
1113 f_service_ <<
David Reiss64f87522009-03-30 19:31:36 +00001114 indent() << "pass" << endl << endl;
1115 indent_down();
Kevin Clark120ff312009-03-03 02:25:50 +00001116 }
David Reiss8cee47c2009-02-07 02:37:05 +00001117 }
1118
Mark Sleee50b3092006-09-04 00:06:47 +00001119 indent_down();
1120 f_service_ <<
1121 endl;
1122}
1123
1124/**
1125 * Generates a service client definition.
1126 *
1127 * @param tservice The service to generate a server for.
1128 */
1129void t_py_generator::generate_service_client(t_service* tservice) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001130 string extends = "";
1131 string extends_client = "";
1132 if (tservice->get_extends() != NULL) {
1133 extends = type_name(tservice->get_extends());
Kevin Clark120ff312009-03-03 02:25:50 +00001134 if (gen_twisted_) {
1135 extends_client = "(" + extends + ".Client)";
1136 } else {
1137 extends_client = extends + ".Client, ";
1138 }
1139 } else {
Roger Meierf4eec7a2011-09-11 18:16:21 +00001140 if (gen_twisted_ && (gen_newstyle_ || gen_dynamic_)) {
1141 extends_client = "(object)";
Kevin Clark120ff312009-03-03 02:25:50 +00001142 }
Mark Sleef0712dc2006-10-25 19:03:57 +00001143 }
1144
Kevin Clark120ff312009-03-03 02:25:50 +00001145 if (gen_twisted_) {
1146 f_service_ <<
1147 "class Client" << extends_client << ":" << endl <<
1148 " implements(Iface)" << endl << endl;
1149 } else {
1150 f_service_ <<
1151 "class Client(" << extends_client << "Iface):" << endl;
1152 }
Mark Sleee50b3092006-09-04 00:06:47 +00001153 indent_up();
David Reiss885c82d2009-03-26 08:40:55 +00001154 generate_python_docstring(f_service_, tservice);
Mark Sleee50b3092006-09-04 00:06:47 +00001155
1156 // Constructor function
Kevin Clark120ff312009-03-03 02:25:50 +00001157 if (gen_twisted_) {
Mark Sleef0712dc2006-10-25 19:03:57 +00001158 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001159 indent() << "def __init__(self, transport, oprot_factory):" << endl;
Mark Sleef0712dc2006-10-25 19:03:57 +00001160 } else {
1161 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001162 indent() << "def __init__(self, iprot, oprot=None):" << endl;
1163 }
1164 if (extends.empty()) {
1165 if (gen_twisted_) {
1166 f_service_ <<
1167 indent() << " self._transport = transport" << endl <<
1168 indent() << " self._oprot_factory = oprot_factory" << endl <<
1169 indent() << " self._seqid = 0" << endl <<
1170 indent() << " self._reqs = {}" << endl <<
1171 endl;
1172 } else {
1173 f_service_ <<
1174 indent() << " self._iprot = self._oprot = iprot" << endl <<
Bryan Duxbury1709d402011-03-23 18:15:19 +00001175 indent() << " if oprot is not None:" << endl <<
Kevin Clark120ff312009-03-03 02:25:50 +00001176 indent() << " self._oprot = oprot" << endl <<
1177 indent() << " self._seqid = 0" << endl <<
1178 endl;
1179 }
1180 } else {
1181 if (gen_twisted_) {
1182 f_service_ <<
1183 indent() << " " << extends << ".Client.__init__(self, transport, oprot_factory)" << endl <<
1184 endl;
1185 } else {
1186 f_service_ <<
1187 indent() << " " << extends << ".Client.__init__(self, iprot, oprot)" << endl <<
1188 endl;
1189 }
Mark Sleef0712dc2006-10-25 19:03:57 +00001190 }
Mark Sleee50b3092006-09-04 00:06:47 +00001191
1192 // Generate client method implementations
1193 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +00001194 vector<t_function*>::const_iterator f_iter;
Mark Sleee50b3092006-09-04 00:06:47 +00001195 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1196 t_struct* arg_struct = (*f_iter)->get_arglist();
1197 const vector<t_field*>& fields = arg_struct->get_members();
1198 vector<t_field*>::const_iterator fld_iter;
1199 string funname = (*f_iter)->get_name();
1200
1201 // Open function
1202 indent(f_service_) <<
1203 "def " << function_signature(*f_iter) << ":" << endl;
1204 indent_up();
David Reiss885c82d2009-03-26 08:40:55 +00001205 generate_python_docstring(f_service_, (*f_iter));
Kevin Clark120ff312009-03-03 02:25:50 +00001206 if (gen_twisted_) {
1207 indent(f_service_) << "self._seqid += 1" << endl;
David Reiss47329252009-03-24 20:01:02 +00001208 if (!(*f_iter)->is_oneway()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001209 indent(f_service_) <<
1210 "d = self._reqs[self._seqid] = defer.Deferred()" << endl;
1211 }
1212 }
1213
1214 indent(f_service_) <<
1215 "self.send_" << funname << "(";
1216
1217 bool first = true;
1218 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1219 if (first) {
1220 first = false;
1221 } else {
1222 f_service_ << ", ";
1223 }
1224 f_service_ << (*fld_iter)->get_name();
1225 }
1226 f_service_ << ")" << endl;
1227
David Reiss47329252009-03-24 20:01:02 +00001228 if (!(*f_iter)->is_oneway()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001229 f_service_ << indent();
1230 if (gen_twisted_) {
1231 f_service_ << "return d" << endl;
1232 } else {
Mark Sleee50b3092006-09-04 00:06:47 +00001233 if (!(*f_iter)->get_returntype()->is_void()) {
1234 f_service_ << "return ";
1235 }
1236 f_service_ <<
1237 "self.recv_" << funname << "()" << endl;
1238 }
Kevin Clark120ff312009-03-03 02:25:50 +00001239 } else {
1240 if (gen_twisted_) {
1241 f_service_ <<
1242 indent() << "return defer.succeed(None)" << endl;
1243 }
1244 }
Mark Sleee50b3092006-09-04 00:06:47 +00001245 indent_down();
1246 f_service_ << endl;
1247
1248 indent(f_service_) <<
1249 "def send_" << function_signature(*f_iter) << ":" << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001250
Mark Sleee50b3092006-09-04 00:06:47 +00001251 indent_up();
1252
Kevin Clark120ff312009-03-03 02:25:50 +00001253 std::string argsname = (*f_iter)->get_name() + "_args";
Mark Sleee50b3092006-09-04 00:06:47 +00001254
Kevin Clark120ff312009-03-03 02:25:50 +00001255 // Serialize the request header
1256 if (gen_twisted_) {
1257 f_service_ <<
1258 indent() << "oprot = self._oprot_factory.getProtocol(self._transport)" << endl <<
1259 indent() <<
1260 "oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)"
1261 << endl;
1262 } else {
Mark Sleee50b3092006-09-04 00:06:47 +00001263 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001264 indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)" << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001265 }
David Reiss382fc302007-08-25 18:01:30 +00001266
Kevin Clark120ff312009-03-03 02:25:50 +00001267 f_service_ <<
1268 indent() << "args = " << argsname << "()" << endl;
1269
1270 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
Mark Sleee50b3092006-09-04 00:06:47 +00001271 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001272 indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << endl;
1273 }
David Reiss382fc302007-08-25 18:01:30 +00001274
Kevin Clark120ff312009-03-03 02:25:50 +00001275 // Write to the stream
1276 if (gen_twisted_) {
1277 f_service_ <<
1278 indent() << "args.write(oprot)" << endl <<
1279 indent() << "oprot.writeMessageEnd()" << endl <<
1280 indent() << "oprot.trans.flush()" << endl;
1281 } else {
Mark Sleee50b3092006-09-04 00:06:47 +00001282 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001283 indent() << "args.write(self._oprot)" << endl <<
1284 indent() << "self._oprot.writeMessageEnd()" << endl <<
David Reiss382fc302007-08-25 18:01:30 +00001285 indent() << "self._oprot.trans.flush()" << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001286 }
Mark Sleee50b3092006-09-04 00:06:47 +00001287
1288 indent_down();
Mark Sleee50b3092006-09-04 00:06:47 +00001289
David Reiss47329252009-03-24 20:01:02 +00001290 if (!(*f_iter)->is_oneway()) {
Mark Sleee50b3092006-09-04 00:06:47 +00001291 std::string resultname = (*f_iter)->get_name() + "_result";
Mark Sleee50b3092006-09-04 00:06:47 +00001292 // Open function
1293 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001294 endl;
1295 if (gen_twisted_) {
1296 f_service_ <<
1297 indent() << "def recv_" << (*f_iter)->get_name() <<
1298 "(self, iprot, mtype, rseqid):" << endl;
1299 } else {
1300 t_struct noargs(program_);
1301 t_function recv_function((*f_iter)->get_returntype(),
1302 string("recv_") + (*f_iter)->get_name(),
1303 &noargs);
1304 f_service_ <<
1305 indent() << "def " << function_signature(&recv_function) << ":" << endl;
1306 }
Mark Sleee50b3092006-09-04 00:06:47 +00001307 indent_up();
1308
Mark Sleef5377b32006-10-10 01:42:59 +00001309 // TODO(mcslee): Validate message reply here, seq ids etc.
Mark Sleee50b3092006-09-04 00:06:47 +00001310
Kevin Clark120ff312009-03-03 02:25:50 +00001311 if (gen_twisted_) {
1312 f_service_ <<
1313 indent() << "d = self._reqs.pop(rseqid)" << endl;
1314 } else {
1315 f_service_ <<
1316 indent() << "(fname, mtype, rseqid) = self._iprot.readMessageBegin()" << endl;
1317 }
Mark Sleeb0060b02007-02-21 05:37:50 +00001318
1319 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001320 indent() << "if mtype == TMessageType.EXCEPTION:" << endl <<
1321 indent() << " x = TApplicationException()" << endl;
1322
1323 if (gen_twisted_) {
1324 f_service_ <<
1325 indent() << " x.read(iprot)" << endl <<
1326 indent() << " iprot.readMessageEnd()" << endl <<
1327 indent() << " return d.errback(x)" << endl <<
1328 indent() << "result = " << resultname << "()" << endl <<
1329 indent() << "result.read(iprot)" << endl <<
1330 indent() << "iprot.readMessageEnd()" << endl;
1331 } else {
1332 f_service_ <<
1333 indent() << " x.read(self._iprot)" << endl <<
1334 indent() << " self._iprot.readMessageEnd()" << endl <<
1335 indent() << " raise x" << endl <<
1336 indent() << "result = " << resultname << "()" << endl <<
1337 indent() << "result.read(self._iprot)" << endl <<
1338 indent() << "self._iprot.readMessageEnd()" << endl;
1339 }
Mark Sleee50b3092006-09-04 00:06:47 +00001340
1341 // Careful, only return _result if not a void function
1342 if (!(*f_iter)->get_returntype()->is_void()) {
1343 f_service_ <<
Bryan Duxbury1709d402011-03-23 18:15:19 +00001344 indent() << "if result.success is not None:" << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001345 if (gen_twisted_) {
1346 f_service_ <<
1347 indent() << " return d.callback(result.success)" << endl;
1348 } else {
1349 f_service_ <<
1350 indent() << " return result.success" << endl;
1351 }
Mark Sleee50b3092006-09-04 00:06:47 +00001352 }
1353
1354 t_struct* xs = (*f_iter)->get_xceptions();
1355 const std::vector<t_field*>& xceptions = xs->get_members();
1356 vector<t_field*>::const_iterator x_iter;
1357 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1358 f_service_ <<
Bryan Duxbury1709d402011-03-23 18:15:19 +00001359 indent() << "if result." << (*x_iter)->get_name() << " is not None:" << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001360 if (gen_twisted_) {
1361 f_service_ <<
1362 indent() << " return d.errback(result." << (*x_iter)->get_name() << ")" << endl;
1363
1364 } else {
1365 f_service_ <<
1366 indent() << " raise result." << (*x_iter)->get_name() << "" << endl;
1367 }
Mark Sleee50b3092006-09-04 00:06:47 +00001368 }
1369
1370 // Careful, only return _result if not a void function
1371 if ((*f_iter)->get_returntype()->is_void()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001372 if (gen_twisted_) {
1373 indent(f_service_) <<
1374 "return d.callback(None)" << endl;
1375 } else {
1376 indent(f_service_) <<
1377 "return" << endl;
1378 }
Mark Sleee50b3092006-09-04 00:06:47 +00001379 } else {
Kevin Clark120ff312009-03-03 02:25:50 +00001380 if (gen_twisted_) {
1381 f_service_ <<
1382 indent() << "return d.errback(TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl;
1383 } else {
1384 f_service_ <<
1385 indent() << "raise TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1386 }
David Reiss382fc302007-08-25 18:01:30 +00001387 }
Mark Sleee50b3092006-09-04 00:06:47 +00001388
Mark Sleed07ce602006-10-27 22:30:15 +00001389 // Close function
1390 indent_down();
David Reiss382fc302007-08-25 18:01:30 +00001391 f_service_ << endl;
1392 }
Mark Sleee50b3092006-09-04 00:06:47 +00001393 }
1394
1395 indent_down();
1396 f_service_ <<
1397 endl;
1398}
1399
1400/**
Mark Slee748e5762006-10-04 21:51:05 +00001401 * Generates a command line tool for making remote requests
1402 *
1403 * @param tservice The service to generate a remote for.
1404 */
1405void t_py_generator::generate_service_remote(t_service* tservice) {
1406 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +00001407 vector<t_function*>::iterator f_iter;
Mark Slee748e5762006-10-04 21:51:05 +00001408
Mark Sleeecf490e2007-02-21 00:05:18 +00001409 string f_remote_name = package_dir_+"/"+service_name_+"-remote";
Mark Slee748e5762006-10-04 21:51:05 +00001410 ofstream f_remote;
1411 f_remote.open(f_remote_name.c_str());
1412
1413 f_remote <<
Mark Slee2c2a6482007-02-21 00:22:33 +00001414 "#!/usr/bin/env python" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001415 py_autogen_comment() << endl <<
1416 "import sys" << endl <<
1417 "import pprint" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001418 "from urlparse import urlparse" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001419 "from thrift.transport import TTransport" << endl <<
1420 "from thrift.transport import TSocket" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001421 "from thrift.transport import THttpClient" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001422 "from thrift.protocol import TBinaryProtocol" << endl <<
1423 endl;
1424
1425 f_remote <<
1426 "import " << service_name_ << endl <<
David Reiss382fc302007-08-25 18:01:30 +00001427 "from ttypes import *" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001428 endl;
1429
1430 f_remote <<
1431 "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl <<
1432 " print ''" << endl <<
Jake Farrellb5d94e02011-10-07 00:14:34 +00001433 " print 'Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] function [arg1 [arg2...]]'" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001434 " print ''" << endl <<
1435 " print 'Functions:'" << endl;
1436 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1437 f_remote <<
1438 " print ' " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "(";
1439 t_struct* arg_struct = (*f_iter)->get_arglist();
1440 const std::vector<t_field*>& args = arg_struct->get_members();
1441 vector<t_field*>::const_iterator a_iter;
1442 int num_args = args.size();
1443 bool first = true;
1444 for (int i = 0; i < num_args; ++i) {
1445 if (first) {
1446 first = false;
1447 } else {
1448 f_remote << ", ";
1449 }
David Reiss382fc302007-08-25 18:01:30 +00001450 f_remote <<
Mark Slee748e5762006-10-04 21:51:05 +00001451 args[i]->get_type()->get_name() << " " << args[i]->get_name();
1452 }
1453 f_remote << ")'" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001454 }
Mark Slee748e5762006-10-04 21:51:05 +00001455 f_remote <<
1456 " print ''" << endl <<
1457 " sys.exit(0)" << endl <<
1458 endl;
1459
1460 f_remote <<
1461 "pp = pprint.PrettyPrinter(indent = 2)" << endl <<
1462 "host = 'localhost'" << endl <<
Mark Slee96a6bbe2006-10-06 22:43:29 +00001463 "port = 9090" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001464 "uri = ''" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001465 "framed = False" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001466 "http = False" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001467 "argi = 1" << endl <<
1468 endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001469 "if sys.argv[argi] == '-h':" << endl <<
Bryan Duxbury1316ed92010-09-02 14:20:01 +00001470 " parts = sys.argv[argi+1].split(':')" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001471 " host = parts[0]" << endl <<
Jake Farrellb5d94e02011-10-07 00:14:34 +00001472 " if len(parts) > 1:" << endl <<
1473 " port = int(parts[1])" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001474 " argi += 2" << endl <<
1475 endl <<
1476 "if sys.argv[argi] == '-u':" << endl <<
1477 " url = urlparse(sys.argv[argi+1])" << endl <<
Bryan Duxbury1316ed92010-09-02 14:20:01 +00001478 " parts = url[1].split(':')" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001479 " host = parts[0]" << endl <<
1480 " if len(parts) > 1:" << endl <<
1481 " port = int(parts[1])" << endl <<
1482 " else:" << endl <<
1483 " port = 80" << endl <<
1484 " uri = url[2]" << endl <<
Bryan Duxbury727d67d2010-09-02 01:00:19 +00001485 " if url[4]:" << endl <<
1486 " uri += '?%s' % url[4]" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001487 " http = True" << endl <<
1488 " argi += 2" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001489 endl <<
1490 "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl <<
1491 " framed = True" << endl <<
1492 " argi += 1" << endl <<
1493 endl <<
1494 "cmd = sys.argv[argi]" << endl <<
1495 "args = sys.argv[argi+1:]" << endl <<
1496 endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001497 "if http:" << endl <<
1498 " transport = THttpClient.THttpClient(host, port, uri)" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001499 "else:" << endl <<
Mark Slee1b65b722007-08-16 00:27:21 +00001500 " socket = TSocket.TSocket(host, port)" << endl <<
1501 " if framed:" << endl <<
1502 " transport = TTransport.TFramedTransport(socket)" << endl <<
1503 " else:" << endl <<
1504 " transport = TTransport.TBufferedTransport(socket)" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001505 "protocol = TBinaryProtocol.TBinaryProtocol(transport)" << endl <<
1506 "client = " << service_name_ << ".Client(protocol)" << endl <<
Mark Slee748e5762006-10-04 21:51:05 +00001507 "transport.open()" << endl <<
1508 endl;
David Reiss382fc302007-08-25 18:01:30 +00001509
Mark Slee748e5762006-10-04 21:51:05 +00001510 // Generate the dispatch methods
1511 bool first = true;
1512
1513 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1514 if (first) {
1515 first = false;
1516 } else {
1517 f_remote << "el";
1518 }
1519
1520 t_struct* arg_struct = (*f_iter)->get_arglist();
1521 const std::vector<t_field*>& args = arg_struct->get_members();
1522 vector<t_field*>::const_iterator a_iter;
1523 int num_args = args.size();
1524
1525 f_remote <<
1526 "if cmd == '" << (*f_iter)->get_name() << "':" << endl <<
1527 " if len(args) != " << num_args << ":" << endl <<
1528 " print '" << (*f_iter)->get_name() << " requires " << num_args << " args'" << endl <<
1529 " sys.exit(1)" << endl <<
1530 " pp.pprint(client." << (*f_iter)->get_name() << "(";
1531 for (int i = 0; i < num_args; ++i) {
Mark Sleeb6200d82007-01-19 19:14:36 +00001532 if (args[i]->get_type()->is_string()) {
Mark Slee748e5762006-10-04 21:51:05 +00001533 f_remote << "args[" << i << "],";
Mark Slee96a6bbe2006-10-06 22:43:29 +00001534 } else {
1535 f_remote << "eval(args[" << i << "]),";
Mark Slee748e5762006-10-04 21:51:05 +00001536 }
1537 }
1538 f_remote << "))" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001539
Mark Slee748e5762006-10-04 21:51:05 +00001540 f_remote << endl;
1541 }
Roger Meier5346e722012-04-13 14:38:19 +00001542
1543 if (functions.size() > 0) {
1544 f_remote << "else:" << endl;
1545 f_remote << " print 'Unrecognized method %s' % cmd" << endl;
1546 f_remote << " sys.exit(1)" << endl;
1547 f_remote << endl;
1548 }
Mark Slee748e5762006-10-04 21:51:05 +00001549
1550 f_remote << "transport.close()" << endl;
David Reiss382fc302007-08-25 18:01:30 +00001551
Mark Slee748e5762006-10-04 21:51:05 +00001552 // Close service file
1553 f_remote.close();
David Reiss382fc302007-08-25 18:01:30 +00001554
Roger Meier508b3172011-09-16 12:02:57 +00001555#ifndef _MSC_VER
1556
Mark Sleef5377b32006-10-10 01:42:59 +00001557 // Make file executable, love that bitwise OR action
Mark Slee748e5762006-10-04 21:51:05 +00001558 chmod(f_remote_name.c_str(),
David Reiss204420f2008-01-11 20:59:03 +00001559 S_IRUSR
1560 | S_IWUSR
1561 | S_IXUSR
1562#ifndef MINGW
1563 | S_IRGRP
1564 | S_IXGRP
1565 | S_IROTH
1566 | S_IXOTH
1567#endif
David Reiss0c90f6f2008-02-06 22:18:40 +00001568 );
Roger Meier508b3172011-09-16 12:02:57 +00001569
1570#endif // _MSC_VER
Mark Slee748e5762006-10-04 21:51:05 +00001571}
1572
1573/**
Mark Sleec9676562006-09-05 17:34:52 +00001574 * Generates a service server definition.
1575 *
1576 * @param tservice The service to generate a server for.
1577 */
1578void t_py_generator::generate_service_server(t_service* tservice) {
1579 // Generate the dispatch methods
1580 vector<t_function*> functions = tservice->get_functions();
David Reiss382fc302007-08-25 18:01:30 +00001581 vector<t_function*>::iterator f_iter;
Mark Sleec9676562006-09-05 17:34:52 +00001582
Mark Sleef0712dc2006-10-25 19:03:57 +00001583 string extends = "";
1584 string extends_processor = "";
1585 if (tservice->get_extends() != NULL) {
1586 extends = type_name(tservice->get_extends());
1587 extends_processor = extends + ".Processor, ";
1588 }
1589
Mark Sleec9676562006-09-05 17:34:52 +00001590 // Generate the header portion
Kevin Clark120ff312009-03-03 02:25:50 +00001591 if (gen_twisted_) {
1592 f_service_ <<
1593 "class Processor(" << extends_processor << "TProcessor):" << endl <<
1594 " implements(Iface)" << endl << endl;
1595 } else {
1596 f_service_ <<
1597 "class Processor(" << extends_processor << "Iface, TProcessor):" << endl;
1598 }
1599
Mark Sleec9676562006-09-05 17:34:52 +00001600 indent_up();
1601
1602 indent(f_service_) <<
Mark Slee5946a182006-10-25 21:38:39 +00001603 "def __init__(self, handler):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001604 indent_up();
Mark Sleef0712dc2006-10-25 19:03:57 +00001605 if (extends.empty()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001606 if (gen_twisted_) {
1607 f_service_ <<
1608 indent() << "self._handler = Iface(handler)" << endl;
1609 } else {
1610 f_service_ <<
1611 indent() << "self._handler = handler" << endl;
1612 }
1613
Mark Sleef0712dc2006-10-25 19:03:57 +00001614 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001615 indent() << "self._processMap = {}" << endl;
Mark Slee6b4783b2006-10-31 05:43:53 +00001616 } else {
Kevin Clark120ff312009-03-03 02:25:50 +00001617 if (gen_twisted_) {
1618 f_service_ <<
1619 indent() << extends << ".Processor.__init__(self, Iface(handler))" << endl;
1620 } else {
1621 f_service_ <<
1622 indent() << extends << ".Processor.__init__(self, handler)" << endl;
1623 }
Mark Sleef0712dc2006-10-25 19:03:57 +00001624 }
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001625 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1626 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001627 indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
David Reiss382fc302007-08-25 18:01:30 +00001628 }
Mark Sleec9676562006-09-05 17:34:52 +00001629 indent_down();
1630 f_service_ << endl;
David Reiss382fc302007-08-25 18:01:30 +00001631
Mark Sleec9676562006-09-05 17:34:52 +00001632 // Generate the server implementation
1633 indent(f_service_) <<
Mark Slee5946a182006-10-25 21:38:39 +00001634 "def process(self, iprot, oprot):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001635 indent_up();
1636
1637 f_service_ <<
Mark Sleeb0060b02007-02-21 05:37:50 +00001638 indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001639
1640 // TODO(mcslee): validate message
1641
Mark Sleef5377b32006-10-10 01:42:59 +00001642 // HOT: dictionary function lookup
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001643 f_service_ <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001644 indent() << "if name not in self._processMap:" << endl <<
Mark Sleeb0060b02007-02-21 05:37:50 +00001645 indent() << " iprot.skip(TType.STRUCT)" << endl <<
1646 indent() << " iprot.readMessageEnd()" << endl <<
1647 indent() << " x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))" << endl <<
1648 indent() << " oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl <<
1649 indent() << " x.write(oprot)" << endl <<
1650 indent() << " oprot.writeMessageEnd()" << endl <<
Kevin Clark120ff312009-03-03 02:25:50 +00001651 indent() << " oprot.trans.flush()" << endl;
Mark Sleeaff9f8e2006-09-07 21:18:27 +00001652
Kevin Clark120ff312009-03-03 02:25:50 +00001653 if (gen_twisted_) {
1654 f_service_ <<
1655 indent() << " return defer.succeed(None)" << endl;
1656 } else {
1657 f_service_ <<
1658 indent() << " return" << endl;
1659 }
1660
Mark Sleec9676562006-09-05 17:34:52 +00001661 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001662 indent() << "else:" << endl;
1663
1664 if (gen_twisted_) {
1665 f_service_ <<
1666 indent() << " return self._processMap[name](self, seqid, iprot, oprot)" << endl;
1667 } else {
1668 f_service_ <<
1669 indent() << " self._processMap[name](self, seqid, iprot, oprot)" << endl;
1670
1671 // Read end of args field, the T_STOP, and the struct close
1672 f_service_ <<
1673 indent() << "return True" << endl;
1674 }
Mark Sleec9676562006-09-05 17:34:52 +00001675
1676 indent_down();
1677 f_service_ << endl;
1678
1679 // Generate the process subfunctions
1680 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1681 generate_process_function(tservice, *f_iter);
1682 }
1683
1684 indent_down();
1685 f_service_ << endl;
1686}
1687
1688/**
1689 * Generates a process function definition.
1690 *
1691 * @param tfunction The function to write a dispatcher for
1692 */
1693void t_py_generator::generate_process_function(t_service* tservice,
1694 t_function* tfunction) {
Roger Meier3b771a12010-11-17 22:11:26 +00001695 (void) tservice;
Mark Sleec9676562006-09-05 17:34:52 +00001696 // Open function
1697 indent(f_service_) <<
1698 "def process_" << tfunction->get_name() <<
Mark Slee5946a182006-10-25 21:38:39 +00001699 "(self, seqid, iprot, oprot):" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001700 indent_up();
1701
1702 string argsname = tfunction->get_name() + "_args";
1703 string resultname = tfunction->get_name() + "_result";
1704
1705 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001706 indent() << "args = " << argsname << "()" << endl <<
1707 indent() << "args.read(iprot)" << endl <<
1708 indent() << "iprot.readMessageEnd()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001709
1710 t_struct* xs = tfunction->get_xceptions();
1711 const std::vector<t_field*>& xceptions = xs->get_members();
1712 vector<t_field*>::const_iterator x_iter;
1713
David Reissc51986f2009-03-24 20:01:25 +00001714 // Declare result for non oneway function
David Reiss47329252009-03-24 20:01:02 +00001715 if (!tfunction->is_oneway()) {
Mark Sleec9676562006-09-05 17:34:52 +00001716 f_service_ <<
Mark Slee5946a182006-10-25 21:38:39 +00001717 indent() << "result = " << resultname << "()" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001718 }
1719
Kevin Clark120ff312009-03-03 02:25:50 +00001720 if (gen_twisted_) {
1721 // Generate the function call
1722 t_struct* arg_struct = tfunction->get_arglist();
1723 const std::vector<t_field*>& fields = arg_struct->get_members();
1724 vector<t_field*>::const_iterator f_iter;
1725
Mark Sleec9676562006-09-05 17:34:52 +00001726 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001727 indent() << "d = defer.maybeDeferred(self._handler." <<
1728 tfunction->get_name() << ", ";
1729 bool first = true;
1730 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1731 if (first) {
1732 first = false;
Mark Sleec9676562006-09-05 17:34:52 +00001733 } else {
Kevin Clark120ff312009-03-03 02:25:50 +00001734 f_service_ << ", ";
Mark Sleec9676562006-09-05 17:34:52 +00001735 }
Kevin Clark120ff312009-03-03 02:25:50 +00001736 f_service_ << "args." << (*f_iter)->get_name();
Mark Sleec9676562006-09-05 17:34:52 +00001737 }
Kevin Clark120ff312009-03-03 02:25:50 +00001738 f_service_ << ")" << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001739
David Reissc51986f2009-03-24 20:01:25 +00001740 // Shortcut out here for oneway functions
David Reiss47329252009-03-24 20:01:02 +00001741 if (tfunction->is_oneway()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001742 f_service_ <<
1743 indent() << "return d" << endl;
1744 indent_down();
1745 f_service_ << endl;
1746 return;
1747 }
1748
Mark Sleec9676562006-09-05 17:34:52 +00001749 f_service_ <<
Kevin Clark120ff312009-03-03 02:25:50 +00001750 indent() <<
1751 "d.addCallback(self.write_results_success_" <<
1752 tfunction->get_name() << ", result, seqid, oprot)" << endl;
1753
1754 if (xceptions.size() > 0) {
1755 f_service_ <<
1756 indent() <<
1757 "d.addErrback(self.write_results_exception_" <<
1758 tfunction->get_name() << ", result, seqid, oprot)" << endl;
1759 }
1760
1761 f_service_ <<
1762 indent() << "return d" << endl;
1763
Mark Sleec9676562006-09-05 17:34:52 +00001764 indent_down();
1765 f_service_ << endl;
Kevin Clark120ff312009-03-03 02:25:50 +00001766
1767 indent(f_service_) <<
1768 "def write_results_success_" << tfunction->get_name() <<
1769 "(self, success, result, seqid, oprot):" << endl;
1770 indent_up();
1771 f_service_ <<
1772 indent() << "result.success = success" << endl <<
1773 indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() <<
1774 "\", TMessageType.REPLY, seqid)" << endl <<
1775 indent() << "result.write(oprot)" << endl <<
1776 indent() << "oprot.writeMessageEnd()" << endl <<
1777 indent() << "oprot.trans.flush()" << endl;
1778 indent_down();
1779 f_service_ << endl;
1780
1781 // Try block for a function with exceptions
David Reiss47329252009-03-24 20:01:02 +00001782 if (!tfunction->is_oneway() && xceptions.size() > 0) {
Kevin Clark120ff312009-03-03 02:25:50 +00001783 indent(f_service_) <<
1784 "def write_results_exception_" << tfunction->get_name() <<
1785 "(self, error, result, seqid, oprot):" << endl;
1786 indent_up();
1787 f_service_ <<
1788 indent() << "try:" << endl;
1789
1790 // Kinda absurd
1791 f_service_ <<
1792 indent() << " error.raiseException()" << endl;
1793 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1794 f_service_ <<
1795 indent() << "except " << type_name((*x_iter)->get_type()) << ", " << (*x_iter)->get_name() << ":" << endl;
David Reiss47329252009-03-24 20:01:02 +00001796 if (!tfunction->is_oneway()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001797 indent_up();
1798 f_service_ <<
1799 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
1800 indent_down();
1801 } else {
1802 f_service_ <<
1803 indent() << "pass" << endl;
1804 }
1805 }
1806 f_service_ <<
1807 indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() <<
1808 "\", TMessageType.REPLY, seqid)" << endl <<
1809 indent() << "result.write(oprot)" << endl <<
1810 indent() << "oprot.writeMessageEnd()" << endl <<
1811 indent() << "oprot.trans.flush()" << endl;
1812 indent_down();
1813 f_service_ << endl;
1814 }
1815 } else {
1816
1817 // Try block for a function with exceptions
1818 if (xceptions.size() > 0) {
1819 f_service_ <<
1820 indent() << "try:" << endl;
1821 indent_up();
1822 }
1823
1824 // Generate the function call
1825 t_struct* arg_struct = tfunction->get_arglist();
1826 const std::vector<t_field*>& fields = arg_struct->get_members();
1827 vector<t_field*>::const_iterator f_iter;
1828
1829 f_service_ << indent();
David Reiss47329252009-03-24 20:01:02 +00001830 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001831 f_service_ << "result.success = ";
1832 }
1833 f_service_ <<
1834 "self._handler." << tfunction->get_name() << "(";
1835 bool first = true;
1836 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1837 if (first) {
1838 first = false;
1839 } else {
1840 f_service_ << ", ";
1841 }
1842 f_service_ << "args." << (*f_iter)->get_name();
1843 }
1844 f_service_ << ")" << endl;
1845
David Reiss47329252009-03-24 20:01:02 +00001846 if (!tfunction->is_oneway() && xceptions.size() > 0) {
Kevin Clark120ff312009-03-03 02:25:50 +00001847 indent_down();
1848 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1849 f_service_ <<
1850 indent() << "except " << type_name((*x_iter)->get_type()) << ", " << (*x_iter)->get_name() << ":" << endl;
David Reiss47329252009-03-24 20:01:02 +00001851 if (!tfunction->is_oneway()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001852 indent_up();
1853 f_service_ <<
1854 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
1855 indent_down();
1856 } else {
1857 f_service_ <<
1858 indent() << "pass" << endl;
1859 }
1860 }
1861 }
1862
David Reissc51986f2009-03-24 20:01:25 +00001863 // Shortcut out here for oneway functions
David Reiss47329252009-03-24 20:01:02 +00001864 if (tfunction->is_oneway()) {
Kevin Clark120ff312009-03-03 02:25:50 +00001865 f_service_ <<
1866 indent() << "return" << endl;
1867 indent_down();
1868 f_service_ << endl;
1869 return;
1870 }
1871
1872 f_service_ <<
1873 indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
1874 indent() << "result.write(oprot)" << endl <<
1875 indent() << "oprot.writeMessageEnd()" << endl <<
1876 indent() << "oprot.trans.flush()" << endl;
1877
1878 // Close function
1879 indent_down();
1880 f_service_ << endl;
Mark Sleec9676562006-09-05 17:34:52 +00001881 }
Mark Sleec9676562006-09-05 17:34:52 +00001882}
1883
1884/**
Mark Sleee50b3092006-09-04 00:06:47 +00001885 * Deserializes a field of any type.
1886 */
1887void t_py_generator::generate_deserialize_field(ofstream &out,
1888 t_field* tfield,
1889 string prefix,
1890 bool inclass) {
Roger Meier3b771a12010-11-17 22:11:26 +00001891 (void) inclass;
David Reisse087a302007-08-23 21:43:25 +00001892 t_type* type = get_true_type(tfield->get_type());
Mark Sleee50b3092006-09-04 00:06:47 +00001893
1894 if (type->is_void()) {
1895 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1896 prefix + tfield->get_name();
1897 }
1898
1899 string name = prefix + tfield->get_name();
1900
1901 if (type->is_struct() || type->is_xception()) {
1902 generate_deserialize_struct(out,
Mark Slee216e7d62006-11-21 00:44:23 +00001903 (t_struct*)type,
Mark Sleee50b3092006-09-04 00:06:47 +00001904 name);
1905 } else if (type->is_container()) {
Mark Slee216e7d62006-11-21 00:44:23 +00001906 generate_deserialize_container(out, type, name);
Mark Sleee50b3092006-09-04 00:06:47 +00001907 } else if (type->is_base_type() || type->is_enum()) {
1908 indent(out) <<
1909 name << " = iprot.";
David Reiss382fc302007-08-25 18:01:30 +00001910
Mark Sleee50b3092006-09-04 00:06:47 +00001911 if (type->is_base_type()) {
1912 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1913 switch (tbase) {
1914 case t_base_type::TYPE_VOID:
1915 throw "compiler error: cannot serialize void field in a struct: " +
1916 name;
1917 break;
David Reiss382fc302007-08-25 18:01:30 +00001918 case t_base_type::TYPE_STRING:
David Reiss95c005a2010-07-01 05:36:25 +00001919 if (((t_base_type*)type)->is_binary() || !gen_utf8strings_) {
1920 out << "readString();";
1921 } else {
1922 out << "readString().decode('utf-8')";
1923 }
Mark Sleee50b3092006-09-04 00:06:47 +00001924 break;
1925 case t_base_type::TYPE_BOOL:
Mark Slee5946a182006-10-25 21:38:39 +00001926 out << "readBool();";
Mark Sleee50b3092006-09-04 00:06:47 +00001927 break;
1928 case t_base_type::TYPE_BYTE:
Mark Slee5946a182006-10-25 21:38:39 +00001929 out << "readByte();";
Mark Sleee50b3092006-09-04 00:06:47 +00001930 break;
1931 case t_base_type::TYPE_I16:
Mark Slee5946a182006-10-25 21:38:39 +00001932 out << "readI16();";
Mark Sleee50b3092006-09-04 00:06:47 +00001933 break;
1934 case t_base_type::TYPE_I32:
Mark Slee5946a182006-10-25 21:38:39 +00001935 out << "readI32();";
Mark Sleee50b3092006-09-04 00:06:47 +00001936 break;
1937 case t_base_type::TYPE_I64:
Mark Slee5946a182006-10-25 21:38:39 +00001938 out << "readI64();";
Mark Sleee50b3092006-09-04 00:06:47 +00001939 break;
Mark Sleec98d0502006-09-06 02:42:25 +00001940 case t_base_type::TYPE_DOUBLE:
Mark Slee5946a182006-10-25 21:38:39 +00001941 out << "readDouble();";
Mark Sleec98d0502006-09-06 02:42:25 +00001942 break;
Mark Sleee50b3092006-09-04 00:06:47 +00001943 default:
David Reissdd7796f2007-08-28 21:09:06 +00001944 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Mark Sleee50b3092006-09-04 00:06:47 +00001945 }
1946 } else if (type->is_enum()) {
Mark Slee5946a182006-10-25 21:38:39 +00001947 out << "readI32();";
Mark Sleee50b3092006-09-04 00:06:47 +00001948 }
1949 out << endl;
1950
1951 } else {
1952 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
Mark Sleef5377b32006-10-10 01:42:59 +00001953 tfield->get_name().c_str(), type->get_name().c_str());
David Reiss382fc302007-08-25 18:01:30 +00001954 }
Mark Sleee50b3092006-09-04 00:06:47 +00001955}
1956
1957/**
Mark Sleef5377b32006-10-10 01:42:59 +00001958 * Generates an unserializer for a struct, calling read()
Mark Sleee50b3092006-09-04 00:06:47 +00001959 */
1960void t_py_generator::generate_deserialize_struct(ofstream &out,
1961 t_struct* tstruct,
1962 string prefix) {
1963 out <<
Mark Sleef0712dc2006-10-25 19:03:57 +00001964 indent() << prefix << " = " << type_name(tstruct) << "()" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001965 indent() << prefix << ".read(iprot)" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001966}
1967
Mark Sleef5377b32006-10-10 01:42:59 +00001968/**
1969 * Serialize a container by writing out the header followed by
1970 * data and then a footer.
1971 */
Mark Sleee50b3092006-09-04 00:06:47 +00001972void t_py_generator::generate_deserialize_container(ofstream &out,
Mark Sleeaeac1922006-09-04 00:20:24 +00001973 t_type* ttype,
1974 string prefix) {
Mark Sleee50b3092006-09-04 00:06:47 +00001975 string size = tmp("_size");
1976 string ktype = tmp("_ktype");
1977 string vtype = tmp("_vtype");
1978 string etype = tmp("_etype");
David Reiss382fc302007-08-25 18:01:30 +00001979
Mark Sleef0712dc2006-10-25 19:03:57 +00001980 t_field fsize(g_type_i32, size);
1981 t_field fktype(g_type_byte, ktype);
1982 t_field fvtype(g_type_byte, vtype);
1983 t_field fetype(g_type_byte, etype);
Mark Sleee50b3092006-09-04 00:06:47 +00001984
1985 // Declare variables, read header
1986 if (ttype->is_map()) {
1987 out <<
Mark Sleeaeac1922006-09-04 00:20:24 +00001988 indent() << prefix << " = {}" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001989 indent() << "(" << ktype << ", " << vtype << ", " << size << " ) = iprot.readMapBegin() " << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001990 } else if (ttype->is_set()) {
1991 out <<
Mark Slee600cdb32006-11-29 22:06:42 +00001992 indent() << prefix << " = set()" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001993 indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001994 } else if (ttype->is_list()) {
1995 out <<
Mark Sleeaeac1922006-09-04 00:20:24 +00001996 indent() << prefix << " = []" << endl <<
Mark Slee5946a182006-10-25 21:38:39 +00001997 indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00001998 }
1999
2000 // For loop iterates over elements
2001 string i = tmp("_i");
2002 indent(out) <<
2003 "for " << i << " in xrange(" << size << "):" << endl;
David Reiss382fc302007-08-25 18:01:30 +00002004
Mark Sleee50b3092006-09-04 00:06:47 +00002005 indent_up();
David Reiss382fc302007-08-25 18:01:30 +00002006
Mark Sleee50b3092006-09-04 00:06:47 +00002007 if (ttype->is_map()) {
2008 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2009 } else if (ttype->is_set()) {
2010 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2011 } else if (ttype->is_list()) {
2012 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
2013 }
David Reiss382fc302007-08-25 18:01:30 +00002014
Mark Sleee50b3092006-09-04 00:06:47 +00002015 indent_down();
2016
2017 // Read container end
2018 if (ttype->is_map()) {
Mark Slee5946a182006-10-25 21:38:39 +00002019 indent(out) << "iprot.readMapEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002020 } else if (ttype->is_set()) {
Mark Slee5946a182006-10-25 21:38:39 +00002021 indent(out) << "iprot.readSetEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002022 } else if (ttype->is_list()) {
Mark Slee5946a182006-10-25 21:38:39 +00002023 indent(out) << "iprot.readListEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002024 }
2025}
2026
2027
2028/**
2029 * Generates code to deserialize a map
2030 */
2031void t_py_generator::generate_deserialize_map_element(ofstream &out,
2032 t_map* tmap,
2033 string prefix) {
2034 string key = tmp("_key");
2035 string val = tmp("_val");
2036 t_field fkey(tmap->get_key_type(), key);
2037 t_field fval(tmap->get_val_type(), val);
2038
Mark Sleee50b3092006-09-04 00:06:47 +00002039 generate_deserialize_field(out, &fkey);
2040 generate_deserialize_field(out, &fval);
2041
2042 indent(out) <<
2043 prefix << "[" << key << "] = " << val << endl;
2044}
2045
Mark Sleef5377b32006-10-10 01:42:59 +00002046/**
2047 * Write a set element
2048 */
Mark Sleee50b3092006-09-04 00:06:47 +00002049void t_py_generator::generate_deserialize_set_element(ofstream &out,
2050 t_set* tset,
2051 string prefix) {
2052 string elem = tmp("_elem");
2053 t_field felem(tset->get_elem_type(), elem);
2054
Mark Sleee50b3092006-09-04 00:06:47 +00002055 generate_deserialize_field(out, &felem);
2056
2057 indent(out) <<
Mark Slee600cdb32006-11-29 22:06:42 +00002058 prefix << ".add(" << elem << ")" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002059}
2060
Mark Sleef5377b32006-10-10 01:42:59 +00002061/**
2062 * Write a list element
2063 */
Mark Sleee50b3092006-09-04 00:06:47 +00002064void t_py_generator::generate_deserialize_list_element(ofstream &out,
2065 t_list* tlist,
2066 string prefix) {
2067 string elem = tmp("_elem");
2068 t_field felem(tlist->get_elem_type(), elem);
2069
Mark Sleee50b3092006-09-04 00:06:47 +00002070 generate_deserialize_field(out, &felem);
2071
2072 indent(out) <<
2073 prefix << ".append(" << elem << ")" << endl;
2074}
2075
2076
2077/**
2078 * Serializes a field of any type.
2079 *
2080 * @param tfield The field to serialize
2081 * @param prefix Name to prepend to field name
2082 */
2083void t_py_generator::generate_serialize_field(ofstream &out,
2084 t_field* tfield,
2085 string prefix) {
David Reisse087a302007-08-23 21:43:25 +00002086 t_type* type = get_true_type(tfield->get_type());
Mark Sleee50b3092006-09-04 00:06:47 +00002087
2088 // Do nothing for void types
2089 if (type->is_void()) {
2090 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
2091 prefix + tfield->get_name();
2092 }
David Reiss382fc302007-08-25 18:01:30 +00002093
Mark Sleee50b3092006-09-04 00:06:47 +00002094 if (type->is_struct() || type->is_xception()) {
2095 generate_serialize_struct(out,
Mark Slee216e7d62006-11-21 00:44:23 +00002096 (t_struct*)type,
Mark Sleee50b3092006-09-04 00:06:47 +00002097 prefix + tfield->get_name());
2098 } else if (type->is_container()) {
2099 generate_serialize_container(out,
Mark Slee216e7d62006-11-21 00:44:23 +00002100 type,
Mark Sleee50b3092006-09-04 00:06:47 +00002101 prefix + tfield->get_name());
2102 } else if (type->is_base_type() || type->is_enum()) {
2103
2104 string name = prefix + tfield->get_name();
2105
2106 indent(out) <<
2107 "oprot.";
David Reiss382fc302007-08-25 18:01:30 +00002108
Mark Sleee50b3092006-09-04 00:06:47 +00002109 if (type->is_base_type()) {
2110 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2111 switch (tbase) {
2112 case t_base_type::TYPE_VOID:
2113 throw
2114 "compiler error: cannot serialize void field in a struct: " + name;
2115 break;
2116 case t_base_type::TYPE_STRING:
David Reiss95c005a2010-07-01 05:36:25 +00002117 if (((t_base_type*)type)->is_binary() || !gen_utf8strings_) {
2118 out << "writeString(" << name << ")";
2119 } else {
2120 out << "writeString(" << name << ".encode('utf-8'))";
2121 }
Mark Sleee50b3092006-09-04 00:06:47 +00002122 break;
2123 case t_base_type::TYPE_BOOL:
Mark Slee5946a182006-10-25 21:38:39 +00002124 out << "writeBool(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00002125 break;
2126 case t_base_type::TYPE_BYTE:
Mark Slee5946a182006-10-25 21:38:39 +00002127 out << "writeByte(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00002128 break;
2129 case t_base_type::TYPE_I16:
Mark Slee5946a182006-10-25 21:38:39 +00002130 out << "writeI16(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00002131 break;
2132 case t_base_type::TYPE_I32:
Mark Slee5946a182006-10-25 21:38:39 +00002133 out << "writeI32(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00002134 break;
2135 case t_base_type::TYPE_I64:
Mark Slee5946a182006-10-25 21:38:39 +00002136 out << "writeI64(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00002137 break;
Mark Sleec98d0502006-09-06 02:42:25 +00002138 case t_base_type::TYPE_DOUBLE:
Mark Slee5946a182006-10-25 21:38:39 +00002139 out << "writeDouble(" << name << ")";
Mark Sleec98d0502006-09-06 02:42:25 +00002140 break;
Mark Sleee50b3092006-09-04 00:06:47 +00002141 default:
David Reissdd7796f2007-08-28 21:09:06 +00002142 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Mark Sleee50b3092006-09-04 00:06:47 +00002143 }
2144 } else if (type->is_enum()) {
Mark Slee5946a182006-10-25 21:38:39 +00002145 out << "writeI32(" << name << ")";
Mark Sleee50b3092006-09-04 00:06:47 +00002146 }
2147 out << endl;
2148 } else {
2149 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
2150 prefix.c_str(),
2151 tfield->get_name().c_str(),
Mark Sleef5377b32006-10-10 01:42:59 +00002152 type->get_name().c_str());
Mark Sleee50b3092006-09-04 00:06:47 +00002153 }
2154}
2155
2156/**
2157 * Serializes all the members of a struct.
2158 *
2159 * @param tstruct The struct to serialize
2160 * @param prefix String prefix to attach to all fields
2161 */
2162void t_py_generator::generate_serialize_struct(ofstream &out,
Mark Sleef5377b32006-10-10 01:42:59 +00002163 t_struct* tstruct,
2164 string prefix) {
Roger Meier3b771a12010-11-17 22:11:26 +00002165 (void) tstruct;
Mark Sleee50b3092006-09-04 00:06:47 +00002166 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002167 prefix << ".write(oprot)" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002168}
2169
2170void t_py_generator::generate_serialize_container(ofstream &out,
Mark Sleef5377b32006-10-10 01:42:59 +00002171 t_type* ttype,
2172 string prefix) {
Mark Sleee50b3092006-09-04 00:06:47 +00002173 if (ttype->is_map()) {
2174 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002175 "oprot.writeMapBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +00002176 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2177 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2178 "len(" << prefix << "))" << endl;
2179 } else if (ttype->is_set()) {
2180 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002181 "oprot.writeSetBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +00002182 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2183 "len(" << prefix << "))" << endl;
2184 } else if (ttype->is_list()) {
2185 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002186 "oprot.writeListBegin(" <<
Mark Sleee50b3092006-09-04 00:06:47 +00002187 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2188 "len(" << prefix << "))" << endl;
2189 }
2190
Mark Sleef5377b32006-10-10 01:42:59 +00002191 if (ttype->is_map()) {
Mark Sleeb39dbc52006-10-31 05:56:27 +00002192 string kiter = tmp("kiter");
2193 string viter = tmp("viter");
David Reiss382fc302007-08-25 18:01:30 +00002194 indent(out) <<
Mark Sleeb39dbc52006-10-31 05:56:27 +00002195 "for " << kiter << "," << viter << " in " << prefix << ".items():" << endl;
Mark Sleef5377b32006-10-10 01:42:59 +00002196 indent_up();
2197 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
2198 indent_down();
2199 } else if (ttype->is_set()) {
Mark Sleeb39dbc52006-10-31 05:56:27 +00002200 string iter = tmp("iter");
David Reiss382fc302007-08-25 18:01:30 +00002201 indent(out) <<
Mark Sleef5377b32006-10-10 01:42:59 +00002202 "for " << iter << " in " << prefix << ":" << endl;
2203 indent_up();
2204 generate_serialize_set_element(out, (t_set*)ttype, iter);
2205 indent_down();
2206 } else if (ttype->is_list()) {
Mark Sleeb39dbc52006-10-31 05:56:27 +00002207 string iter = tmp("iter");
David Reiss382fc302007-08-25 18:01:30 +00002208 indent(out) <<
Mark Sleef5377b32006-10-10 01:42:59 +00002209 "for " << iter << " in " << prefix << ":" << endl;
2210 indent_up();
2211 generate_serialize_list_element(out, (t_list*)ttype, iter);
2212 indent_down();
2213 }
David Reiss382fc302007-08-25 18:01:30 +00002214
Mark Sleee50b3092006-09-04 00:06:47 +00002215 if (ttype->is_map()) {
2216 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002217 "oprot.writeMapEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002218 } else if (ttype->is_set()) {
2219 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002220 "oprot.writeSetEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002221 } else if (ttype->is_list()) {
2222 indent(out) <<
Mark Slee5946a182006-10-25 21:38:39 +00002223 "oprot.writeListEnd()" << endl;
Mark Sleee50b3092006-09-04 00:06:47 +00002224 }
2225}
2226
2227/**
2228 * Serializes the members of a map.
2229 *
2230 */
2231void t_py_generator::generate_serialize_map_element(ofstream &out,
2232 t_map* tmap,
2233 string kiter,
2234 string viter) {
2235 t_field kfield(tmap->get_key_type(), kiter);
2236 generate_serialize_field(out, &kfield, "");
2237
2238 t_field vfield(tmap->get_val_type(), viter);
2239 generate_serialize_field(out, &vfield, "");
2240}
2241
2242/**
2243 * Serializes the members of a set.
2244 */
2245void t_py_generator::generate_serialize_set_element(ofstream &out,
2246 t_set* tset,
2247 string iter) {
2248 t_field efield(tset->get_elem_type(), iter);
2249 generate_serialize_field(out, &efield, "");
2250}
2251
2252/**
2253 * Serializes the members of a list.
2254 */
2255void t_py_generator::generate_serialize_list_element(ofstream &out,
2256 t_list* tlist,
2257 string iter) {
2258 t_field efield(tlist->get_elem_type(), iter);
2259 generate_serialize_field(out, &efield, "");
2260}
2261
2262/**
David Reiss885c82d2009-03-26 08:40:55 +00002263 * Generates the docstring for a given struct.
2264 */
2265void t_py_generator::generate_python_docstring(ofstream& out,
2266 t_struct* tstruct) {
2267 generate_python_docstring(out, tstruct, tstruct, "Attributes");
2268}
2269
2270/**
2271 * Generates the docstring for a given function.
2272 */
2273void t_py_generator::generate_python_docstring(ofstream& out,
2274 t_function* tfunction) {
2275 generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
2276}
2277
2278/**
2279 * Generates the docstring for a struct or function.
2280 */
2281void t_py_generator::generate_python_docstring(ofstream& out,
2282 t_doc* tdoc,
2283 t_struct* tstruct,
2284 const char* subheader) {
2285 bool has_doc = false;
2286 stringstream ss;
2287 if (tdoc->has_doc()) {
2288 has_doc = true;
2289 ss << tdoc->get_doc();
2290 }
2291
2292 const vector<t_field*>& fields = tstruct->get_members();
2293 if (fields.size() > 0) {
2294 if (has_doc) {
2295 ss << endl;
2296 }
2297 has_doc = true;
2298 ss << subheader << ":\n";
2299 vector<t_field*>::const_iterator p_iter;
2300 for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
2301 t_field* p = *p_iter;
2302 ss << " - " << p->get_name();
2303 if (p->has_doc()) {
2304 ss << ": " << p->get_doc();
2305 } else {
2306 ss << endl;
2307 }
2308 }
2309 }
2310
2311 if (has_doc) {
2312 generate_docstring_comment(out,
2313 "\"\"\"\n",
2314 "", ss.str(),
2315 "\"\"\"\n");
2316 }
2317}
2318
2319/**
2320 * Generates the docstring for a generic object.
2321 */
2322void t_py_generator::generate_python_docstring(ofstream& out,
2323 t_doc* tdoc) {
2324 if (tdoc->has_doc()) {
2325 generate_docstring_comment(out,
2326 "\"\"\"\n",
2327 "", tdoc->get_doc(),
2328 "\"\"\"\n");
2329 }
2330}
2331
2332/**
David Reiss46bb4ae2009-01-14 22:34:15 +00002333 * Declares an argument, which may include initialization as necessary.
Mark Sleee50b3092006-09-04 00:06:47 +00002334 *
David Reiss46bb4ae2009-01-14 22:34:15 +00002335 * @param tfield The field
Mark Sleee50b3092006-09-04 00:06:47 +00002336 */
David Reiss46bb4ae2009-01-14 22:34:15 +00002337string t_py_generator::declare_argument(t_field* tfield) {
2338 std::ostringstream result;
2339 result << tfield->get_name() << "=";
2340 if (tfield->get_value() != NULL) {
2341 result << "thrift_spec[" <<
2342 tfield->get_key() << "][4]";
2343 } else {
2344 result << "None";
2345 }
2346 return result.str();
2347}
2348
2349/**
2350 * Renders a field default value, returns None otherwise.
2351 *
2352 * @param tfield The field
2353 */
2354string t_py_generator::render_field_default_value(t_field* tfield) {
David Reisse087a302007-08-23 21:43:25 +00002355 t_type* type = get_true_type(tfield->get_type());
Mark Slee7ff32452007-02-01 05:26:18 +00002356 if (tfield->get_value() != NULL) {
David Reiss46bb4ae2009-01-14 22:34:15 +00002357 return render_const_value(type, tfield->get_value());
Mark Slee7ff32452007-02-01 05:26:18 +00002358 } else {
David Reiss46bb4ae2009-01-14 22:34:15 +00002359 return "None";
Mark Sleee50b3092006-09-04 00:06:47 +00002360 }
Mark Sleee50b3092006-09-04 00:06:47 +00002361}
2362
2363/**
2364 * Renders a function signature of the form 'type name(args)'
2365 *
2366 * @param tfunction Function definition
2367 * @return String of rendered function definition
2368 */
2369string t_py_generator::function_signature(t_function* tfunction,
2370 string prefix) {
Mark Sleef5377b32006-10-10 01:42:59 +00002371 // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
Mark Sleee50b3092006-09-04 00:06:47 +00002372 return
2373 prefix + tfunction->get_name() +
2374 "(self, " + argument_list(tfunction->get_arglist()) + ")";
2375}
2376
2377/**
Kevin Clark120ff312009-03-03 02:25:50 +00002378 * Renders an interface function signature of the form 'type name(args)'
2379 *
2380 * @param tfunction Function definition
2381 * @return String of rendered function definition
2382 */
2383string t_py_generator::function_signature_if(t_function* tfunction,
2384 string prefix) {
2385 // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
2386 string signature = prefix + tfunction->get_name() + "(";
2387 if (!gen_twisted_) {
2388 signature += "self, ";
2389 }
2390 signature += argument_list(tfunction->get_arglist()) + ")";
2391 return signature;
2392}
2393
2394
2395/**
Mark Sleee50b3092006-09-04 00:06:47 +00002396 * Renders a field list
2397 */
2398string t_py_generator::argument_list(t_struct* tstruct) {
2399 string result = "";
2400
2401 const vector<t_field*>& fields = tstruct->get_members();
2402 vector<t_field*>::const_iterator f_iter;
2403 bool first = true;
2404 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2405 if (first) {
2406 first = false;
2407 } else {
2408 result += ", ";
2409 }
2410 result += (*f_iter)->get_name();
2411 }
2412 return result;
2413}
2414
Mark Sleef0712dc2006-10-25 19:03:57 +00002415string t_py_generator::type_name(t_type* ttype) {
2416 t_program* program = ttype->get_program();
David Reissa7fc0922009-02-07 02:37:09 +00002417 if (ttype->is_service()) {
Bryan Duxburyc39817c2010-08-20 16:45:13 +00002418 return get_real_py_module(program, gen_twisted_) + "." + ttype->get_name();
David Reissa7fc0922009-02-07 02:37:09 +00002419 }
Mark Sleef0712dc2006-10-25 19:03:57 +00002420 if (program != NULL && program != program_) {
Bryan Duxburyc39817c2010-08-20 16:45:13 +00002421 return get_real_py_module(program, gen_twisted_) + ".ttypes." + ttype->get_name();
Mark Sleef0712dc2006-10-25 19:03:57 +00002422 }
2423 return ttype->get_name();
2424}
2425
Mark Sleee50b3092006-09-04 00:06:47 +00002426/**
Mark Sleef5377b32006-10-10 01:42:59 +00002427 * Converts the parse type to a Python tyoe
Mark Sleee50b3092006-09-04 00:06:47 +00002428 */
2429string t_py_generator::type_to_enum(t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00002430 type = get_true_type(type);
David Reiss382fc302007-08-25 18:01:30 +00002431
Mark Sleee50b3092006-09-04 00:06:47 +00002432 if (type->is_base_type()) {
2433 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2434 switch (tbase) {
2435 case t_base_type::TYPE_VOID:
2436 throw "NO T_VOID CONSTRUCT";
2437 case t_base_type::TYPE_STRING:
2438 return "TType.STRING";
2439 case t_base_type::TYPE_BOOL:
2440 return "TType.BOOL";
2441 case t_base_type::TYPE_BYTE:
2442 return "TType.BYTE";
2443 case t_base_type::TYPE_I16:
2444 return "TType.I16";
2445 case t_base_type::TYPE_I32:
2446 return "TType.I32";
2447 case t_base_type::TYPE_I64:
2448 return "TType.I64";
Mark Sleec98d0502006-09-06 02:42:25 +00002449 case t_base_type::TYPE_DOUBLE:
2450 return "TType.DOUBLE";
Mark Sleee50b3092006-09-04 00:06:47 +00002451 }
2452 } else if (type->is_enum()) {
2453 return "TType.I32";
2454 } else if (type->is_struct() || type->is_xception()) {
2455 return "TType.STRUCT";
2456 } else if (type->is_map()) {
2457 return "TType.MAP";
2458 } else if (type->is_set()) {
2459 return "TType.SET";
2460 } else if (type->is_list()) {
2461 return "TType.LIST";
2462 }
2463
2464 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2465}
David Reiss382fc302007-08-25 18:01:30 +00002466
2467/** See the comment inside generate_py_struct_definition for what this is. */
2468string t_py_generator::type_to_spec_args(t_type* ttype) {
2469 while (ttype->is_typedef()) {
2470 ttype = ((t_typedef*)ttype)->get_type();
2471 }
2472
2473 if (ttype->is_base_type() || ttype->is_enum()) {
2474 return "None";
2475 } else if (ttype->is_struct() || ttype->is_xception()) {
2476 return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)";
2477 } else if (ttype->is_map()) {
2478 return "(" +
2479 type_to_enum(((t_map*)ttype)->get_key_type()) + "," +
2480 type_to_spec_args(((t_map*)ttype)->get_key_type()) + "," +
2481 type_to_enum(((t_map*)ttype)->get_val_type()) + "," +
2482 type_to_spec_args(((t_map*)ttype)->get_val_type()) +
2483 ")";
2484
2485 } else if (ttype->is_set()) {
2486 return "(" +
2487 type_to_enum(((t_set*)ttype)->get_elem_type()) + "," +
2488 type_to_spec_args(((t_set*)ttype)->get_elem_type()) +
2489 ")";
2490
2491 } else if (ttype->is_list()) {
2492 return "(" +
2493 type_to_enum(((t_list*)ttype)->get_elem_type()) + "," +
2494 type_to_spec_args(((t_list*)ttype)->get_elem_type()) +
2495 ")";
2496 }
2497
2498 throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
2499}
David Reiss558e3992008-03-27 21:41:40 +00002500
2501
2502THRIFT_REGISTER_GENERATOR(py, "Python",
Kevin Clark120ff312009-03-03 02:25:50 +00002503" new_style: Generate new-style classes.\n" \
Jake Farrell64621852011-07-11 13:47:25 +00002504" twisted: Generate Twisted-friendly RPC services.\n" \
Roger Meierf4eec7a2011-09-11 18:16:21 +00002505" utf8strings: Encode/decode strings using utf8 in the generated code.\n" \
2506" slots: Generate code using slots for instance members.\n" \
2507" dynamic: Generate dynamic code, less code generated but slower.\n" \
2508" dynbase=CLS Derive generated classes from class CLS instead of TBase.\n" \
2509" dynexc=CLS Derive generated exceptions from CLS instead of TExceptionBase.\n" \
2510" dynimport='from foo.bar import CLS'\n" \
2511" Add an import line to generated code to find the dynbase class.\n")
Roger Meier0069cc42010-10-13 18:10:18 +00002512