diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 1c551e999db..35615c74e33 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -729,6 +729,9 @@ struct IDLOptions { // Whether to generate numpy helpers. bool python_gen_numpy; + // Use snake-case for field names in the Python object API. + bool python_fields_snake_case; + bool ts_omit_entrypoint; ProtoIdGapAction proto_id_gap_action; @@ -856,6 +859,7 @@ struct IDLOptions { python_no_type_prefix_suffix(false), python_typing(false), python_gen_numpy(true), + python_fields_snake_case(false), ts_omit_entrypoint(false), proto_id_gap_action(ProtoIdGapAction::WARNING), mini_reflect(IDLOptions::kNone), diff --git a/src/flatc.cpp b/src/flatc.cpp index 612f797cc18..07310c2c5f2 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -266,6 +266,8 @@ const static FlatCOption flatc_options[] = { {"", "python-decode-obj-api-strings", "", "Decode bytes to strings for the Python Object API"}, {"", "python-gen-numpy", "", "Whether to generate numpy helpers."}, + {"", "python-fields-snake-case", "", + "Generate Python fields using snake_case naming convention."}, {"", "ts-omit-entrypoint", "", "Omit emission of namespace entrypoint file"}, {"", "file-names-only", "", @@ -708,6 +710,8 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc, } else if (arg == "--no-python-gen-numpy" || arg == "--python-gen-numpy=false") { opts.python_gen_numpy = false; + } else if (arg == "--python-fields-snake-case") { + opts.python_fields_snake_case = true; } else if (arg == "--ts-omit-entrypoint") { opts.ts_omit_entrypoint = true; } else if (arg == "--annotate-sparse-vectors") { diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index 4c48b21b17d..285c7728bbf 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -48,12 +48,22 @@ typedef std::set ImportMap; static const CommentConfig def_comment = {nullptr, "#", nullptr}; static const std::string Indent = " "; +inline Namer::Config PythonNamerConfig(const Namer::Config& input, + const IDLOptions& opts, + const std::string& path) { + auto cfg = WithFlagOptions(input, opts, path); + if (opts.python_fields_snake_case) { + cfg.fields = Case::kSnake; + } + return cfg; +} + class PythonStubGenerator { public: PythonStubGenerator(const Parser& parser, const std::string& path, const Version& version) : parser_{parser}, - namer_{WithFlagOptions(kStubConfig, parser.opts, path), + namer_{PythonNamerConfig(kStubConfig, parser.opts, path), Keywords(version)}, version_(version) {} @@ -698,7 +708,7 @@ class PythonGenerator : public BaseGenerator { : BaseGenerator(parser, path, file_name, "" /* not used */, "" /* not used */, "py"), float_const_gen_("float('nan')", "float('inf')", "float('-inf')"), - namer_(WithFlagOptions(kConfig, parser.opts, path), Keywords(version)) { + namer_(PythonNamerConfig(kConfig, parser.opts, path), Keywords(version)) { } // Most field accessors need to retrieve and test the field offset first, @@ -1321,7 +1331,7 @@ class PythonGenerator : public BaseGenerator { } else { code += IsArray(field_type) ? " " : ""; code += indent + " builder.Prepend" + GenMethod(field) + "("; - code += nameprefix + namer_.Variable(field); + code += nameprefix + namer_.Field(field); size_t array_cnt = index + (IsArray(field_type) ? 1 : 0); for (size_t i = 0; in_array && i < array_cnt; i++) { code += "[_idx" + NumToString(i) + "-1]";