void t_py_generator::generate_process_function()

in compiler/cpp/src/thrift/generate/t_py_generator.cc [2045:2313]


void t_py_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
  (void)tservice;
  // Open function
  if (gen_tornado_) {
    f_service_ << indent() << "@gen.coroutine" << '\n' << indent() << "def process_"
               << tfunction->get_name() << "(self, seqid, iprot, oprot):" << '\n';
  } else {
    f_service_ << indent() << "def process_" << tfunction->get_name()
               << "(self, seqid, iprot, oprot):" << '\n';
  }

  indent_up();

  string argsname = tfunction->get_name() + "_args";
  string resultname = tfunction->get_name() + "_result";

  f_service_ << indent() << "args = " << argsname << "()" << '\n' << indent() << "args.read(iprot)"
             << '\n' << indent() << "iprot.readMessageEnd()" << '\n';

  t_struct* xs = tfunction->get_xceptions();
  const std::vector<t_field*>& xceptions = xs->get_members();
  vector<t_field*>::const_iterator x_iter;

  // Declare result for non oneway function
  if (!tfunction->is_oneway()) {
    f_service_ << indent() << "result = " << resultname << "()" << '\n';
  }

  if (gen_twisted_) {
    // Generate the function call
    t_struct* arg_struct = tfunction->get_arglist();
    const std::vector<t_field*>& fields = arg_struct->get_members();
    vector<t_field*>::const_iterator f_iter;

    f_service_ << indent() << "d = defer.maybeDeferred(self._handler." << tfunction->get_name()
               << ", ";
    bool first = true;
    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
      if (first) {
        first = false;
      } else {
        f_service_ << ", ";
      }
      f_service_ << "args." << (*f_iter)->get_name();
    }
    f_service_ << ")" << '\n';

    if (tfunction->is_oneway()) {
      f_service_ << indent() << "d.addErrback(self.handle_exception_" << tfunction->get_name()
                 << ", seqid)" << '\n';
    } else {
      f_service_ << indent() << "d.addCallback(self.write_results_success_" << tfunction->get_name()
                 << ", result, seqid, oprot)" << '\n'
                 << indent() << "d.addErrback(self.write_results_exception_"
                 << tfunction->get_name() << ", result, seqid, oprot)" << '\n';
    }
    f_service_ << indent() << "return d" << '\n' << '\n';

    indent_down();

    if (tfunction->is_oneway()) {
      indent(f_service_) << "def handle_exception_" << tfunction->get_name()
                         << "(self, error, seqid):" << '\n';
    } else {
      indent(f_service_) << "def write_results_success_" << tfunction->get_name()
                         << "(self, success, result, seqid, oprot):" << '\n';
      indent_up();
      if (!tfunction->get_returntype()->is_void()) {
        f_service_ << indent() << "result.success = success" << '\n';
      }
      f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
                 << "\", TMessageType.REPLY, seqid)" << '\n'
                 << indent() << "result.write(oprot)" << '\n'
                 << indent() << "oprot.writeMessageEnd()" << '\n'
                 << indent() << "oprot.trans.flush()" << '\n'
                 << '\n';
      indent_down();

      indent(f_service_) << "def write_results_exception_" << tfunction->get_name()
                         << "(self, error, result, seqid, oprot):" << '\n';
    }
    indent_up();
    if (!tfunction->is_oneway()) {
      f_service_ << indent() << "msg_type = TMessageType.REPLY" << '\n';
    }
    f_service_ << indent() << "try:" << '\n';

    // Kinda absurd
    f_service_ << indent() << indent_str() << "error.raiseException()" << '\n';
    if (!tfunction->is_oneway()) {
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        const string& xname = (*x_iter)->get_name();
        f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname
                   << ":" << '\n';
        indent_up();
        f_service_ << indent() << "result." << xname << " = " << xname << '\n';
        indent_down();
      }
    }
    f_service_ << indent() << "except TTransport.TTransportException:" << '\n'
               << indent() << indent_str() << "raise" << '\n';
    if (!tfunction->is_oneway()) {
      f_service_ << indent() << "except TApplicationException as ex:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('TApplication exception in handler')" << '\n'
                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << '\n'
                 << indent() << indent_str() << "result = ex" << '\n'
                 << indent() << "except Exception:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('Unexpected exception in handler')" << '\n'
                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << '\n'
                 << indent() << indent_str()
                 << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, "
                    "'Internal error')"
                 << '\n'
                 << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
                 << "\", msg_type, seqid)" << '\n'
                 << indent() << "result.write(oprot)" << '\n'
                 << indent() << "oprot.writeMessageEnd()" << '\n'
                 << indent() << "oprot.trans.flush()" << '\n';
    } else {
      f_service_ << indent() << "except Exception:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('Exception in oneway handler')" << '\n';
    }
    indent_down();

  } else if (gen_tornado_) {
    // Generate the function call
    t_struct* arg_struct = tfunction->get_arglist();
    const std::vector<t_field*>& fields = arg_struct->get_members();
    vector<t_field*>::const_iterator f_iter;

    if (!tfunction->is_oneway()) {
      indent(f_service_) << "msg_type = TMessageType.REPLY" << '\n';
    }
    f_service_ << indent() << "try:" << '\n';
    indent_up();
    f_service_ << indent();
    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
      f_service_ << "result.success = ";
    }
    f_service_ << "yield gen.maybe_future(self._handler." << tfunction->get_name() << "(";
    bool first = true;
    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
      if (first) {
        first = false;
      } else {
        f_service_ << ", ";
      }
      f_service_ << "args." << (*f_iter)->get_name();
    }
    f_service_ << "))" << '\n';

    indent_down();
    if (!tfunction->is_oneway()) {
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        const string& xname = (*x_iter)->get_name();
        f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname
                   << ":" << '\n'
                   << indent() << indent_str() << "result." << xname << " = " << xname << '\n';
      }
    }
    f_service_ << indent() << "except TTransport.TTransportException:" << '\n'
               << indent() << indent_str() << "raise" << '\n';
    if (!tfunction->is_oneway()) {
      f_service_ << indent() << "except TApplicationException as ex:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('TApplication exception in handler')" << '\n'
                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << '\n'
                 << indent() << indent_str() << "result = ex" << '\n'
                 << indent() << "except Exception:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('Unexpected exception in handler')" << '\n'
                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << '\n'
                 << indent() << indent_str()
                 << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, "
                    "'Internal error')"
                 << '\n';
    } else {
      f_service_ << indent() << "except Exception:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('Exception in oneway handler')" << '\n';
    }

    if (!tfunction->is_oneway()) {
      f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
                 << "\", msg_type, seqid)" << '\n'
                 << indent() << "result.write(oprot)" << '\n'
                 << indent() << "oprot.writeMessageEnd()" << '\n'
                 << indent() << "oprot.trans.flush()" << '\n';
    }

    // Close function
    indent_down();

  } else { // py
    // Try block for a function with exceptions
    // It also catches arbitrary exceptions raised by handler method to propagate them to the client
    f_service_ << indent() << "try:" << '\n';
    indent_up();

    // Generate the function call
    t_struct* arg_struct = tfunction->get_arglist();
    const std::vector<t_field*>& fields = arg_struct->get_members();
    vector<t_field*>::const_iterator f_iter;

    f_service_ << indent();
    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
      f_service_ << "result.success = ";
    }
    f_service_ << "self._handler." << tfunction->get_name() << "(";
    bool first = true;
    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
      if (first) {
        first = false;
      } else {
        f_service_ << ", ";
      }
      f_service_ << "args." << (*f_iter)->get_name();
    }
    f_service_ << ")" << '\n';
    if (!tfunction->is_oneway()) {
      f_service_ << indent() << "msg_type = TMessageType.REPLY" << '\n';
    }

    indent_down();
    f_service_ << indent()
               << "except TTransport.TTransportException:" << '\n'
               << indent() << indent_str() << "raise" << '\n';

    if (!tfunction->is_oneway()) {
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        const string& xname = (*x_iter)->get_name();
        f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname
                   << ":" << '\n';
        indent_up();
        f_service_ << indent() << "msg_type = TMessageType.REPLY" << '\n';
        f_service_ << indent() << "result." << xname << " = " << xname << '\n';
        indent_down();
      }

      f_service_ << indent() << "except TApplicationException as ex:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('TApplication exception in handler')" << '\n'
                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << '\n'
                 << indent() << indent_str() << "result = ex" << '\n'
                 << indent() << "except Exception:" << '\n'
                 << indent() << indent_str()
                 << "logging.exception('Unexpected exception in handler')" << '\n'
                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << '\n'
                 << indent() << indent_str()
                 << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, "
                    "'Internal error')"
                 << '\n'
                 << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
                 << "\", msg_type, seqid)" << '\n'
                 << indent() << "result.write(oprot)" << '\n'
                 << indent() << "oprot.writeMessageEnd()" << '\n'
                 << indent() << "oprot.trans.flush()" << '\n';
    } else {
      f_service_ << indent() << "except Exception:" << '\n'
                 << indent() << indent_str() << "logging.exception('Exception in oneway handler')" << '\n';
    }

    // Close function
    indent_down();
  }
}