Repository: google/flatbuffers
File: grpc/src/compiler/python_generator.cc (C++)

Code before:

  const Parser &parser_;
  const IdlNamer namer_;
  const Version version_;
  const std::string &path_;
};

class StubGenerator : public BaseGenerator {
 public:
  StubGenerator(const Parser &parser, const std::string &path,
                const Version &version)
      : BaseGenerator(parser, kStubConfig, path, version) {}

  bool Generate() {
    Imports imports;
    std::stringstream stub;
    std::string ns_name{};
    for (const ServiceDef *service : parser_.services_.vec) {
      Generate(stub, service, &imports);
      ns_name = NamespaceDir(*service->defined_namespace, false);
    }

    std::string sanitized_suffix{ parser_.opts.grpc_filename_suffix };
    std::replace(sanitized_suffix.begin(), sanitized_suffix.end(), '.', '_');
    std::string filename =
        namer_.config_.output_path + ns_name + kPathSeparator +
        StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" +
        sanitized_suffix + namer_.config_.filename_extension;

    return SaveStub(filename, imports, stub.str());
  }

 private:
  void Generate(std::stringstream &ss, const ServiceDef *service,
                Imports *imports) {
    imports->Import("grpc");

    ss << "class " << service->name << "Stub(object):\n"
       << "  def __init__(self, channel: grpc.Channel) -> None: ...\n";

    for (const RPCCall *method : service->calls.vec) {
      std::string request = "bytes";
      std::string response = "bytes";

      if (parser_.opts.grpc_python_typed_handlers) {
        request = namer_.Type(*method->request);
        response = namer_.Type(*method->response);

        imports->Import(ModuleFor(method->request), request);
        imports->Import(ModuleFor(method->response), response);
      }

Review comment (suggestion):
Can this be done outside of the generator and passed in `namer_.config_.output_path`? This will not work with our Google-internal setup as we need to know or be able to override the path to the generated file without looking into the content of the original `.fbs` file.

Code after:

  const Parser &parser_;
  const IdlNamer namer_;
  const Version version_;
  const std::string &path_;
};

class StubGenerator : public BaseGenerator {
 public:
  StubGenerator(const Parser &parser, const std::string &path,
                const Version &version)
      : BaseGenerator(parser, kStubConfig, path, version) {}

  bool Generate() {
    Imports imports;
    std::stringstream stub;
    std::string ns_name{};
    for (const ServiceDef *service : parser_.services_.vec) {
      Generate(stub, service, &imports);
      ns_name = NamespaceDir(*service->defined_namespace, false);
    }

    std::string sanitized_suffix{ parser_.opts.grpc_filename_suffix };
    std::replace(sanitized_suffix.begin(), sanitized_suffix.end(), '.', '_');
    std::string filename =
        ns_name + kPathSeparator +
        StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" +
        sanitized_suffix + namer_.config_.filename_extension;

    return SaveStub(filename, imports, stub.str());
  }

 private:
  void Generate(std::stringstream &ss, const ServiceDef *service,
                Imports *imports) {
    imports->Import("grpc");

    ss << "class " << service->name << "Stub(object):\n"
       << "  def __init__(self, channel: grpc.Channel) -> None: ...\n";

    for (const RPCCall *method : service->calls.vec) {
      std::string request = "bytes";
      std::string response = "bytes";

      if (parser_.opts.grpc_python_typed_handlers) {
        request = namer_.Type(*method->request);
        response = namer_.Type(*method->response);

        imports->Import(ModuleFor(method->request), request);
        imports->Import(ModuleFor(method->response), response);
      }