Bugfix: grpc python code generation location and file suffix (#8359)

* clang-format

* [Python] Replace . with _ in grpc filename suffix

Having filenames with . like `file.fb.grcp`
is not great for Python. Since dots are used for namespaces.
Replacing all of them with _ eg suffix `foo.bar.baz` will become
`foo_bar_baz`.

Restoring the previous default `_fb` suffix.

* [Python] Use namespace in path

This fixes a regression introduced with:
fb9afbafc7
And generates the grpc file in the namespace folder again.

* Sync commandline docs with web docs
This commit is contained in:
Felix
2025-06-25 07:52:40 +02:00
committed by GitHub
parent dfd92124aa
commit 31beb0fb2f
3 changed files with 71 additions and 39 deletions

View File

@@ -131,7 +131,7 @@ list of `FILES...`.
- `--gen-mutable` : Generate additional non-const accessors for mutating - `--gen-mutable` : Generate additional non-const accessors for mutating
FlatBuffers in-place. FlatBuffers in-place.
- `--gen-onefile` : Generate single output file for C#, Go, and Python. - `--gen-onefile` : Generate a single output file for C#, Go, Java, Kotlin and Python.
- `--gen-name-strings` : Generate type name functions for C++. - `--gen-name-strings` : Generate type name functions for C++.

View File

@@ -1,52 +1,54 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! # Generated by the gRPC FlatBuffers compiler. DO NOT EDIT!
import flatbuffers
import grpc import grpc
from models.HelloReply import HelloReply
from models.HelloRequest import HelloRequest
class GreeterStub(object): class GreeterStub(object):
""" Interface exported by the server. """ '''Interface exported by the server.'''
def __init__(self, channel): def __init__(self, channel):
""" Constructor. '''Constructor.
Args: Args:
channel: A grpc.Channel. channel: A grpc.Channel.
""" '''
self.SayHello = channel.unary_unary( self.SayHello = channel.unary_unary(
"/models.Greeter/SayHello" method='/models.Greeter/SayHello')
)
self.SayManyHellos = channel.unary_stream( self.SayManyHellos = channel.unary_stream(
"/models.Greeter/SayManyHellos" method='/models.Greeter/SayManyHellos')
)
class GreeterServicer(object): class GreeterServicer(object):
""" Interface exported by the server. """ '''Interface exported by the server.'''
def SayHello(self, request, context): def SayHello(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!') context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!') raise NotImplementedError('Method not implemented!')
def SayManyHellos(self, request, context): def SayManyHellos(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!') context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!') raise NotImplementedError('Method not implemented!')
def add_GreeterServicer_to_server(servicer, server): def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = { rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler( 'SayHello': grpc.unary_unary_rpc_method_handler(
servicer.SayHello servicer.SayHello),
),
'SayManyHellos': grpc.unary_stream_rpc_method_handler( 'SayManyHellos': grpc.unary_stream_rpc_method_handler(
servicer.SayManyHellos servicer.SayManyHellos),
),
} }
generic_handler = grpc.method_handlers_generic_handler( generic_handler = grpc.method_handlers_generic_handler(
'models.Greeter', rpc_method_handlers) 'models.Greeter', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,)) server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -37,12 +37,14 @@ namespace grpc {
namespace { namespace {
bool ClientStreaming(const RPCCall *method) { bool ClientStreaming(const RPCCall *method) {
const Value *val = method->attributes.Lookup("streaming"); const Value *val = method->attributes.Lookup("streaming");
return val != nullptr && (val->constant == "client" || val->constant == "bidi"); return val != nullptr &&
(val->constant == "client" || val->constant == "bidi");
} }
bool ServerStreaming(const RPCCall *method) { bool ServerStreaming(const RPCCall *method) {
const Value *val = method->attributes.Lookup("streaming"); const Value *val = method->attributes.Lookup("streaming");
return val != nullptr && (val->constant == "server" || val->constant == "bidi"); return val != nullptr &&
(val->constant == "server" || val->constant == "bidi");
} }
void FormatImports(std::stringstream &ss, const Imports &imports) { void FormatImports(std::stringstream &ss, const Imports &imports) {
@@ -103,9 +105,10 @@ class BaseGenerator {
protected: protected:
BaseGenerator(const Parser &parser, const Namer::Config &config, BaseGenerator(const Parser &parser, const Namer::Config &config,
const std::string &path, const Version &version) const std::string &path, const Version &version)
: parser_{parser}, : parser_{ parser },
namer_{WithFlagOptions(config, parser.opts, path), Keywords(version)}, namer_{ WithFlagOptions(config, parser.opts, path), Keywords(version) },
version_{version} {} version_{ version },
path_(path) {}
protected: protected:
std::string ModuleForFile(const std::string &file) const { std::string ModuleForFile(const std::string &file) const {
@@ -115,15 +118,34 @@ class BaseGenerator {
return module; return module;
} }
template <typename T> template<typename T> std::string ModuleFor(const T *def) const {
std::string ModuleFor(const T *def) const {
if (parser_.opts.one_file) return ModuleForFile(def->file); if (parser_.opts.one_file) return ModuleForFile(def->file);
return namer_.NamespacedType(*def); return namer_.NamespacedType(*def);
} }
std::string NamespaceDir(const Parser &parser, const std::string &path,
const Namespace &ns, const bool dasherize) {
EnsureDirExists(path);
if (parser.opts.one_file) return path;
std::string namespace_dir = path; // Either empty or ends in separator.
auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
namespace_dir +=
!dasherize ? *it : ConvertCase(*it, Case::kDasher, Case::kUpperCamel);
namespace_dir += kPathSeparator;
EnsureDirExists(namespace_dir);
}
return namespace_dir;
}
std::string NamespaceDir(const Namespace &ns, const bool dasherize) {
return NamespaceDir(parser_, path_, ns, dasherize);
}
const Parser &parser_; const Parser &parser_;
const IdlNamer namer_; const IdlNamer namer_;
const Version version_; const Version version_;
const std::string &path_;
}; };
class StubGenerator : public BaseGenerator { class StubGenerator : public BaseGenerator {
@@ -135,14 +157,18 @@ class StubGenerator : public BaseGenerator {
bool Generate() { bool Generate() {
Imports imports; Imports imports;
std::stringstream stub; std::stringstream stub;
std::string ns_name{};
for (const ServiceDef *service : parser_.services_.vec) { for (const ServiceDef *service : parser_.services_.vec) {
Generate(stub, service, &imports); 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 = std::string filename =
namer_.config_.output_path + ns_name + kPathSeparator +
StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" + StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" +
parser_.opts.grpc_filename_suffix + namer_.config_.filename_extension; sanitized_suffix + namer_.config_.filename_extension;
return SaveStub(filename, imports, stub.str()); return SaveStub(filename, imports, stub.str());
} }
@@ -247,16 +273,20 @@ class ServiceGenerator : public BaseGenerator {
<< '\n'; << '\n';
} }
std::string ns_name{};
for (const ServiceDef *service : parser_.services_.vec) { for (const ServiceDef *service : parser_.services_.vec) {
GenerateStub(ss, service, &imports); GenerateStub(ss, service, &imports);
GenerateServicer(ss, service, &imports); GenerateServicer(ss, service, &imports);
GenerateRegister(ss, service, &imports); GenerateRegister(ss, 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 = std::string filename =
namer_.config_.output_path + ns_name + kPathSeparator +
StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" + StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" +
parser_.opts.grpc_filename_suffix + namer_.config_.filename_extension; sanitized_suffix + namer_.config_.filename_extension;
return SaveService(filename, imports, ss.str()); return SaveService(filename, imports, ss.str());
} }
@@ -365,13 +395,13 @@ class ServiceGenerator : public BaseGenerator {
bool Generate(const Parser &parser, const std::string &path, bool Generate(const Parser &parser, const std::string &path,
const Version &version) { const Version &version) {
ServiceGenerator generator{parser, path, version}; ServiceGenerator generator{ parser, path, version };
return generator.Generate(); return generator.Generate();
} }
bool GenerateStub(const Parser &parser, const std::string &path, bool GenerateStub(const Parser &parser, const std::string &path,
const Version &version) { const Version &version) {
StubGenerator generator{parser, path, version}; StubGenerator generator{ parser, path, version };
return generator.Generate(); return generator.Generate();
} }