THRIFT-282. Generate doccstrings for Python classes

Docstrings are generated for
  - enums (but not enum members)
  - structures and structure fields
  - service interfaces
  - functions and function arguments


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@758558 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
index a5c6151..cde70a9 100644
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -137,6 +137,20 @@
                                           t_list*     tlist,
                                           std::string iter);
 
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_struct* tstruct);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_function* tfunction);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_doc*    tdoc,
+                                          t_struct* tstruct,
+                                          const char* subheader);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_doc* tdoc);
+
   /**
    * Helper rendering functions
    */
@@ -328,6 +342,7 @@
     (gen_newstyle_ ? "(object)" : "") <<
     ":" << endl;
   indent_up();
+  generate_python_docstring(f_types_, tenum);
 
   vector<t_enum_value*> constants = tenum->get_constants();
   vector<t_enum_value*>::iterator c_iter;
@@ -530,6 +545,7 @@
   out <<
     ":" << endl;
   indent_up();
+  generate_python_docstring(out, tstruct);
 
   out << endl;
 
@@ -903,6 +919,7 @@
   f_service_ <<
     "class Iface" << extends_if << ":" << endl;
   indent_up();
+  generate_python_docstring(f_service_, tservice);
   vector<t_function*> functions = tservice->get_functions();
   if (functions.empty()) {
     f_service_ <<
@@ -911,7 +928,9 @@
     vector<t_function*>::iterator f_iter;
     for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
       f_service_ <<
-        indent() << "def " << function_signature_if(*f_iter) << ":" << endl <<
+        indent() << "def " << function_signature_if(*f_iter) << ":" << endl;
+      generate_python_docstring(f_service_, (*f_iter));
+      f_service_ <<
         indent() << "  pass" << endl << endl;
     }
   }
@@ -951,6 +970,7 @@
       "class Client(" << extends_client << "Iface):" << endl;
   }
   indent_up();
+  generate_python_docstring(f_service_, tservice);
 
   // Constructor function
   if (gen_twisted_) {
@@ -1001,6 +1021,7 @@
     indent(f_service_) <<
       "def " << function_signature(*f_iter) << ":" << endl;
     indent_up();
+    generate_python_docstring(f_service_, (*f_iter));
     if (gen_twisted_) {
       indent(f_service_) << "self._seqid += 1" << endl;
       if (!(*f_iter)->is_oneway()) {
@@ -2033,6 +2054,76 @@
 }
 
 /**
+ * Generates the docstring for a given struct.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_struct* tstruct) {
+  generate_python_docstring(out, tstruct, tstruct, "Attributes");
+}
+
+/**
+ * Generates the docstring for a given function.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_function* tfunction) {
+  generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
+}
+
+/**
+ * Generates the docstring for a struct or function.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_doc*    tdoc,
+                                               t_struct* tstruct,
+                                               const char* subheader) {
+  bool has_doc = false;
+  stringstream ss;
+  if (tdoc->has_doc()) {
+    has_doc = true;
+    ss << tdoc->get_doc();
+  }
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  if (fields.size() > 0) {
+    if (has_doc) {
+      ss << endl;
+    }
+    has_doc = true;
+    ss << subheader << ":\n";
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ss << " - " << p->get_name();
+      if (p->has_doc()) {
+        ss << ": " << p->get_doc();
+      } else {
+        ss << endl;
+      }
+    }
+  }
+
+  if (has_doc) {
+    generate_docstring_comment(out,
+      "\"\"\"\n",
+      "", ss.str(),
+      "\"\"\"\n");
+  }
+}
+
+/**
+ * Generates the docstring for a generic object.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out,
+      "\"\"\"\n",
+      "", tdoc->get_doc(),
+      "\"\"\"\n");
+  }
+}
+
+/**
  * Declares an argument, which may include initialization as necessary.
  *
  * @param tfield The field