Extract Python naming helper functions into a separate names library.

PiperOrigin-RevId: 961053716
This commit is contained in:
Jason Aragorn Tobias Lunn 2026-08-07 12:07:31 -07:00 committed by Copybara-Service
parent 620c9cf483
commit b2e184385f
10 changed files with 130 additions and 54 deletions

View file

@ -35,6 +35,7 @@ google/protobuf/compiler/php/names.h
google/protobuf/compiler/plugin.h google/protobuf/compiler/plugin.h
google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h
google/protobuf/compiler/plugin.proto google/protobuf/compiler/plugin.proto
google/protobuf/compiler/python/names.h
google/protobuf/compiler/retention.h google/protobuf/compiler/retention.h
google/protobuf/compiler/scc.h google/protobuf/compiler/scc.h
google/protobuf/compiler/subprocess.h google/protobuf/compiler/subprocess.h

View file

@ -222,6 +222,7 @@ cc_dist_library(
"//src/google/protobuf/compiler/java:names", "//src/google/protobuf/compiler/java:names",
"//src/google/protobuf/compiler/objectivec:names", "//src/google/protobuf/compiler/objectivec:names",
"//src/google/protobuf/compiler/php:names", "//src/google/protobuf/compiler/php:names",
"//src/google/protobuf/compiler/python:names",
], ],
) )

View file

@ -27,6 +27,22 @@ cc_binary(
], ],
) )
cc_library(
name = "names",
srcs = ["names.cc"],
hdrs = ["names.h"],
copts = COPTS,
strip_include_prefix = "/src",
visibility = ["//visibility:public"],
deps = [
"//src/google/protobuf",
"//src/google/protobuf:port",
"//src/google/protobuf/compiler:code_generator",
"@abseil-cpp//absl/log:absl_check",
"@abseil-cpp//absl/strings",
],
)
cc_library( cc_library(
name = "python", name = "python",
srcs = [ srcs = [
@ -47,6 +63,7 @@ cc_library(
"@com_github_grpc_grpc//tools/distrib/python/grpcio_tools:__subpackages__", "@com_github_grpc_grpc//tools/distrib/python/grpcio_tools:__subpackages__",
], ],
deps = [ deps = [
":names",
"//src/google/protobuf", "//src/google/protobuf",
"//src/google/protobuf:port", "//src/google/protobuf:port",
"//src/google/protobuf/compiler:code_generator", "//src/google/protobuf/compiler:code_generator",

View file

@ -44,6 +44,7 @@
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/python/helpers.h" #include "google/protobuf/compiler/python/helpers.h"
#include "google/protobuf/compiler/python/names.h"
#include "google/protobuf/compiler/python/pyi_generator.h" #include "google/protobuf/compiler/python/pyi_generator.h"
#include "google/protobuf/compiler/retention.h" #include "google/protobuf/compiler/retention.h"
#include "google/protobuf/compiler/versions.h" #include "google/protobuf/compiler/versions.h"
@ -62,19 +63,6 @@ namespace compiler {
namespace python { namespace python {
namespace { namespace {
// Returns the alias we assign to the module of the given .proto filename
// when importing. See testPackageInitializationImport in
// third_party/py/google/protobuf/internal/reflection_test.py
// to see why we need the alias.
std::string ModuleAlias(absl::string_view filename) {
std::string module_name = ModuleName(filename);
// We can't have dots in the module name, so we replace each with _dot_.
// But that could lead to a collision between a.b and a_dot_b, so we also
// duplicate each underscore.
absl::StrReplaceAll({{"_", "__"}}, &module_name);
absl::StrReplaceAll({{".", "_dot_"}}, &module_name);
return module_name;
}
// Name of the class attribute where we store the Python // Name of the class attribute where we store the Python
// descriptor.Descriptor instance for the generated class. // descriptor.Descriptor instance for the generated class.
@ -311,7 +299,7 @@ bool Generator::Generate(const FileDescriptor* file,
if (GeneratingDescriptorProto()) { if (GeneratingDescriptorProto()) {
printer_->Outdent(); printer_->Outdent();
} }
std::string module_name = ModuleName(file->name()); std::string module_name = ModuleName(file);
if (!opensource_runtime_) { if (!opensource_runtime_) {
module_name = module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix)); std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -396,8 +384,8 @@ void Generator::PrintTopBoilerplate() const {
printer_->Print("\n\n"); printer_->Print("\n\n");
} }
std::string Generator::ImportModuleName(absl::string_view filename) const { std::string Generator::ImportModuleName(const FileDescriptor* file) const {
std::string module_name = ModuleName(filename); std::string module_name = ModuleName(file);
if (!opensource_runtime_) { if (!opensource_runtime_) {
module_name = module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix)); std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -409,10 +397,8 @@ std::string Generator::ImportModuleName(absl::string_view filename) const {
void Generator::PrintImports() const { void Generator::PrintImports() const {
bool has_importlib = false; bool has_importlib = false;
for (int i = 0; i < file_->dependency_count(); ++i) { for (int i = 0; i < file_->dependency_count(); ++i) {
absl::string_view filename = file_->dependency(i)->name(); std::string module_name = ImportModuleName(file_->dependency(i));
std::string module_alias = ModuleAlias(file_->dependency(i));
std::string module_name = ImportModuleName(filename);
std::string module_alias = ModuleAlias(filename);
if (ContainsPythonKeyword(module_name)) { if (ContainsPythonKeyword(module_name)) {
// If the module path contains a Python keyword, we have to quote the // If the module path contains a Python keyword, we have to quote the
// module name and import it using importlib. Otherwise the usual kind of // module name and import it using importlib. Otherwise the usual kind of
@ -446,8 +432,7 @@ void Generator::PrintImports() const {
// Print public imports. // Print public imports.
for (int i = 0; i < file_->public_dependency_count(); ++i) { for (int i = 0; i < file_->public_dependency_count(); ++i) {
std::string module_name = std::string module_name = ImportModuleName(file_->public_dependency(i));
ImportModuleName(file_->public_dependency(i)->name());
printer_->Print("from $module$ import *\n", "module", module_name); printer_->Print("from $module$ import *\n", "module", module_name);
} }
printer_->Print("\n"); printer_->Print("\n");
@ -601,7 +586,7 @@ void Generator::PrintFileDescriptor() const {
if (file_->dependency_count() != 0) { if (file_->dependency_count() != 0) {
printer_->Print(",\ndependencies=["); printer_->Print(",\ndependencies=[");
for (int i = 0; i < file_->dependency_count(); ++i) { for (int i = 0; i < file_->dependency_count(); ++i) {
std::string module_alias = ModuleAlias(file_->dependency(i)->name()); std::string module_alias = ModuleAlias(file_->dependency(i));
printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias", printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
module_alias); module_alias);
} }
@ -610,8 +595,7 @@ void Generator::PrintFileDescriptor() const {
if (file_->public_dependency_count() > 0) { if (file_->public_dependency_count() > 0) {
printer_->Print(",\npublic_dependencies=["); printer_->Print(",\npublic_dependencies=[");
for (int i = 0; i < file_->public_dependency_count(); ++i) { for (int i = 0; i < file_->public_dependency_count(); ++i) {
std::string module_alias = std::string module_alias = ModuleAlias(file_->public_dependency(i));
ModuleAlias(file_->public_dependency(i)->name());
printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias", printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
module_alias); module_alias);
} }
@ -741,7 +725,7 @@ void Generator::PrintDescriptorKeyAndModuleName(
std::string name = ModuleLevelServiceDescriptorName(descriptor); std::string name = ModuleLevelServiceDescriptorName(descriptor);
printer_->Print("$descriptor_key$ = $descriptor_name$,\n", "descriptor_key", printer_->Print("$descriptor_key$ = $descriptor_name$,\n", "descriptor_key",
kDescriptorKey, "descriptor_name", name); kDescriptorKey, "descriptor_name", name);
std::string module_name = ModuleName(file_->name()); std::string module_name = ModuleName(file_);
if (!opensource_runtime_) { if (!opensource_runtime_) {
module_name = module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix)); std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -937,7 +921,7 @@ void Generator::PrintMessage(const Descriptor& message_descriptor,
m["descriptor_key"] = kDescriptorKey; m["descriptor_key"] = kDescriptorKey;
m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n"); printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n");
std::string module_name = ModuleName(file_->name()); std::string module_name = ModuleName(file_);
if (!opensource_runtime_) { if (!opensource_runtime_) {
module_name = module_name =
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix)); std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
@ -1275,7 +1259,7 @@ std::string Generator::ModuleLevelDescriptorName(
// We now have the name relative to its own module. Also qualify with // We now have the name relative to its own module. Also qualify with
// the module name iff this descriptor is from a different .proto file. // the module name iff this descriptor is from a different .proto file.
if (descriptor.file() != file_) { if (descriptor.file() != file_) {
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name); name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
} }
return name; return name;
} }
@ -1288,7 +1272,7 @@ std::string Generator::ModuleLevelMessageName(
const Descriptor& descriptor) const { const Descriptor& descriptor) const {
std::string name = NamePrefixedWithNestedTypes(descriptor, "."); std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
if (descriptor.file() != file_) { if (descriptor.file() != file_) {
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name); name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
} }
return name; return name;
} }
@ -1300,7 +1284,7 @@ std::string Generator::ModuleLevelServiceDescriptorName(
std::string name = absl::StrCat("_", descriptor.name()); std::string name = absl::StrCat("_", descriptor.name());
absl::AsciiStrToUpper(&name); absl::AsciiStrToUpper(&name);
if (descriptor.file() != file_) { if (descriptor.file() != file_) {
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name); name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
} }
return name; return name;
} }
@ -1521,8 +1505,8 @@ void Generator::FixOptionsForMessage(const Descriptor& descriptor,
void Generator::CopyPublicDependenciesAliases( void Generator::CopyPublicDependenciesAliases(
absl::string_view copy_from, const FileDescriptor* file) const { absl::string_view copy_from, const FileDescriptor* file) const {
for (int i = 0; i < file->public_dependency_count(); ++i) { for (int i = 0; i < file->public_dependency_count(); ++i) {
std::string module_name = ModuleName(file->public_dependency(i)->name()); std::string module_name = ModuleName(file->public_dependency(i));
std::string module_alias = ModuleAlias(file->public_dependency(i)->name()); std::string module_alias = ModuleAlias(file->public_dependency(i));
// There's no module alias in the dependent file if it was generated by // There's no module alias in the dependent file if it was generated by
// an old protoc (less than 3.0.0-alpha-1). Use module name in this // an old protoc (less than 3.0.0-alpha-1). Use module name in this
// situation. // situation.

View file

@ -82,7 +82,7 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
private: private:
GeneratorOptions ParseParameter(absl::string_view parameter, GeneratorOptions ParseParameter(absl::string_view parameter,
std::string* error) const; std::string* error) const;
std::string ImportModuleName(absl::string_view filename) const; std::string ImportModuleName(const FileDescriptor* file) const;
void PrintImports() const; void PrintImports() const;
template <typename DescriptorT> template <typename DescriptorT>
std::string GetResolvedFeatures(const DescriptorT& descriptor) const; std::string GetResolvedFeatures(const DescriptorT& descriptor) const;

View file

@ -14,11 +14,12 @@
#include "absl/log/absl_check.h" #include "absl/log/absl_check.h"
#include "absl/strings/escaping.h" #include "absl/strings/escaping.h"
#include "absl/strings/match.h" #include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h" #include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h" #include "absl/strings/str_split.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/strings/strip.h" #include "absl/strings/strip.h"
#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/python/names.h"
#include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/descriptor.pb.h"
@ -27,18 +28,6 @@ namespace protobuf {
namespace compiler { namespace compiler {
namespace python { namespace python {
// Returns the Python module name expected for a given .proto filename.
std::string ModuleName(absl::string_view filename) {
std::string basename = StripProto(filename);
absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
return absl::StrCat(basename, "_pb2");
}
std::string StrippedModuleName(absl::string_view filename) {
std::string module_name = ModuleName(filename);
return module_name;
}
// Keywords reserved by the Python language. // Keywords reserved by the Python language.
const char* const kKeywords[] = { const char* const kKeywords[] = {
"False", "None", "True", "and", "as", "assert", "False", "None", "True", "and", "as", "assert",
@ -74,7 +63,7 @@ std::string ResolveKeyword(absl::string_view name) {
std::string GetFileName(const FileDescriptor* file_des, std::string GetFileName(const FileDescriptor* file_des,
absl::string_view suffix) { absl::string_view suffix) {
std::string module_name = ModuleName(file_des->name()); std::string module_name = ModuleName(file_des);
std::string filename = module_name; std::string filename = module_name;
absl::StrReplaceAll({{".", "/"}}, &filename); absl::StrReplaceAll({{".", "/"}}, &filename);
absl::StrAppend(&filename, suffix); absl::StrAppend(&filename, suffix);

View file

@ -10,18 +10,18 @@
#include <string> #include <string>
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/descriptor.pb.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google { namespace google {
namespace protobuf { namespace protobuf {
namespace compiler { namespace compiler {
namespace python { namespace python {
std::string ModuleName(absl::string_view filename);
std::string StrippedModuleName(absl::string_view filename);
bool ContainsPythonKeyword(absl::string_view module_name); bool ContainsPythonKeyword(absl::string_view module_name);
bool IsPythonKeyword(absl::string_view name); bool IsPythonKeyword(absl::string_view name);
std::string ResolveKeyword(absl::string_view name); std::string ResolveKeyword(absl::string_view name);
@ -40,4 +40,6 @@ std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__ #endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__

View file

@ -0,0 +1,45 @@
#include "google/protobuf/compiler/python/names.h"
#include <string>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "google/protobuf/compiler/code_generator.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace python {
// Returns the Python module name expected for a given .proto filename.
std::string ModuleName(const FileDescriptor* file) {
std::string basename = StripProto(file->name());
absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
return absl::StrCat(basename, "_pb2");
}
std::string StrippedModuleName(const FileDescriptor* file) {
std::string module_name = ModuleName(file);
return module_name;
}
// Returns the alias we assign to the module of the given .proto filename
// when importing. See testPackageInitializationImport in
// third_party/py/google/protobuf/internal/reflection_test.py
// to see why we need the alias.
std::string ModuleAlias(const FileDescriptor* file) {
std::string module_name = ModuleName(file);
// We can't have dots in the module name, so we replace each with _dot_.
// But that could lead to a collision between a.b and a_dot_b, so we also
// duplicate each underscore.
absl::StrReplaceAll({{"_", "__"}}, &module_name);
absl::StrReplaceAll({{".", "_dot_"}}, &module_name);
return module_name;
}
} // namespace python
} // namespace compiler
} // namespace protobuf
} // namespace google

View file

@ -0,0 +1,36 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
#define GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
#include <string>
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
class FileDescriptor;
namespace compiler {
namespace python {
// Returns the Python module name expected for a given .proto filename.
PROTOC_EXPORT std::string ModuleName(const FileDescriptor* file);
// Returns the stripped Python module name expected for a given .proto filename.
PROTOC_EXPORT std::string StrippedModuleName(const FileDescriptor* file);
// Returns the alias we assign to the module of the given .proto filename
// when importing. See testPackageInitializationImport in
// third_party/py/google/protobuf/internal/reflection_test.py
// to see why we need the alias.
PROTOC_EXPORT std::string ModuleAlias(const FileDescriptor* file);
} // namespace python
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__

View file

@ -24,6 +24,7 @@
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/python/helpers.h" #include "google/protobuf/compiler/python/helpers.h"
#include "google/protobuf/compiler/python/names.h"
#include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h" #include "google/protobuf/io/printer.h"
@ -45,7 +46,7 @@ std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
std::string module_alias; std::string module_alias;
const absl::string_view filename = descriptor.file()->name(); const absl::string_view filename = descriptor.file()->name();
if (import_map_.find(filename) == import_map_.end()) { if (import_map_.find(filename) == import_map_.end()) {
std::string module_name = ModuleName(descriptor.file()->name()); std::string module_name = ModuleName(descriptor.file());
std::vector<absl::string_view> tokens = absl::StrSplit(module_name, '.'); std::vector<absl::string_view> tokens = absl::StrSplit(module_name, '.');
module_alias = absl::StrCat("_", tokens.back()); module_alias = absl::StrCat("_", tokens.back());
} else { } else {
@ -151,7 +152,7 @@ void PyiGenerator::PrintImportForDescriptor(
const FileDescriptor& desc, absl::flat_hash_set<std::string>* seen_aliases, const FileDescriptor& desc, absl::flat_hash_set<std::string>* seen_aliases,
bool* has_importlib) const { bool* has_importlib) const {
const absl::string_view filename = desc.name(); const absl::string_view filename = desc.name();
std::string module_name_owned = StrippedModuleName(filename); std::string module_name_owned = StrippedModuleName(&desc);
absl::string_view module_name(module_name_owned); absl::string_view module_name(module_name_owned);
size_t last_dot_pos = module_name.rfind('.'); size_t last_dot_pos = module_name.rfind('.');
std::string alias = absl::StrCat("_", module_name.substr(last_dot_pos + 1)); std::string alias = absl::StrCat("_", module_name.substr(last_dot_pos + 1));
@ -296,7 +297,7 @@ void PyiGenerator::PrintImports() const {
// Public imports // Public imports
for (int i = 0; i < file_->public_dependency_count(); ++i) { for (int i = 0; i < file_->public_dependency_count(); ++i) {
const FileDescriptor* public_dep = file_->public_dependency(i); const FileDescriptor* public_dep = file_->public_dependency(i);
std::string module_name = StrippedModuleName(public_dep->name()); std::string module_name = StrippedModuleName(public_dep);
// Top level messages in public imports // Top level messages in public imports
for (int i = 0; i < public_dep->message_type_count(); ++i) { for (int i = 0; i < public_dep->message_type_count(); ++i) {
printer_->Print( printer_->Print(
@ -404,7 +405,7 @@ std::string PyiGenerator::GetFieldType(
std::string name = ModuleLevelName(*field_des.message_type()); std::string name = ModuleLevelName(*field_des.message_type());
if ((containing_des.containing_type() != nullptr && if ((containing_des.containing_type() != nullptr &&
name == containing_des.name())) { name == containing_des.name())) {
std::string module = ModuleName(field_des.file()->name()); std::string module = ModuleName(field_des.file());
name = absl::StrCat(module, ".", name); name = absl::StrCat(module, ".", name);
} }
return name; return name;