thrift/compiler/generate/t_mstch_python_generator.cc (905 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <iterator> #include <string> #include <utility> #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> #include <thrift/compiler/ast/t_service.h> #include <thrift/compiler/generate/common.h> #include <thrift/compiler/generate/t_mstch_generator.h> #include <thrift/compiler/generate/t_mstch_objects.h> #include <thrift/compiler/lib/cpp2/util.h> #include <thrift/compiler/lib/py3/util.h> namespace apache { namespace thrift { namespace compiler { namespace { std::vector<std::string> get_py3_namespace(const t_program* prog) { return split_namespace(prog->get_namespace("py3")); } std::string get_py3_namespace_with_name_and_prefix( const t_program* prog, const std::string& prefix) { std::ostringstream ss; if (!prefix.empty()) { ss << prefix << "."; } for (const auto& name : split_namespace(prog->get_namespace("py3"))) { ss << name << "."; } ss << prog->name(); return ss.str(); } bool is_type_iobuf(const std::string& name) { return name == "folly::IOBuf" || name == "std::unique_ptr<folly::IOBuf>"; } bool is_func_supported(const t_function* func) { return !func->returns_stream() && !func->returns_sink() && !func->get_returntype()->is_service(); } class mstch_python_type : public mstch_type { public: mstch_python_type( const t_type* type, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, const t_program* prog) : mstch_type(type, std::move(generators), std::move(cache), pos), prog_{prog} { register_methods( this, { {"type:module_path", &mstch_python_type::module_path}, {"type:program_name", &mstch_python_type::program_name}, {"type:metadata_path", &mstch_python_type::metadata_path}, {"type:py3_namespace", &mstch_python_type::py3_namespace}, {"type:need_module_path?", &mstch_python_type::need_module_path}, {"type:external_program?", &mstch_python_type::is_external_program}, {"type:integer?", &mstch_python_type::is_integer}, {"type:iobuf?", &mstch_python_type::is_iobuf}, }); } mstch::node module_path() { return get_py3_namespace_with_name_and_prefix( get_type_program(), get_option("root_module_prefix")) + ".lite_types"; } mstch::node program_name() { return get_type_program()->name(); } mstch::node metadata_path() { return get_py3_namespace_with_name_and_prefix( get_type_program(), get_option("root_module_prefix")) + ".lite_metadata"; } mstch::node py3_namespace() { std::ostringstream ss; for (const auto& path : get_py3_namespace(get_type_program())) { ss << path << "."; } return ss.str(); } mstch::node need_module_path() { if (!has_option("is_types_file")) { return true; } if (const t_program* prog = type_->program()) { if (prog != prog_) { return true; } } return false; } mstch::node is_external_program() { auto p = type_->program(); return p && p != prog_; } mstch::node is_integer() { return type_->is_any_int() || type_->is_byte(); } // Supporting legacy py3 cpp.type iobuf declaration here mstch::node is_iobuf() { return type_->has_annotation("py3.iobuf") || is_type_iobuf(type_->get_annotation("cpp2.type")) || is_type_iobuf(type_->get_annotation("cpp.type")); } protected: const t_program* get_type_program() const { if (const t_program* p = type_->program()) { return p; } return prog_; } const t_program* prog_; }; class mstch_python_const_value : public mstch_const_value { public: mstch_python_const_value( t_const_value const* const_value, t_const const* current_const, t_type const* expected_type, std::shared_ptr<mstch_generators const> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t index) : mstch_const_value( const_value, current_const, expected_type, std::move(generators), std::move(cache), pos, index) { register_methods( this, { {"value:py3_string_value", &mstch_python_const_value::string_value}, {"value:py3_string?", &mstch_python_const_value::is_string}, {"value:py3_binary?", &mstch_python_const_value::is_binary}, {"value:const_enum_type", &mstch_python_const_value::const_enum_type}, {"value:value_for_bool?", &mstch_python_const_value::value_for_bool}, {"value:value_for_floating_point?", &mstch_python_const_value::value_for_floating_point}, {"value:list_elem_type", &mstch_python_const_value::list_elem_type}, {"value:value_for_set?", &mstch_python_const_value::value_for_set}, {"value:map_key_type", &mstch_python_const_value::map_key_type}, {"value:map_val_type", &mstch_python_const_value::map_val_type}, }); } mstch::node is_string() { auto& ttype = const_value_->ttype(); return type_ == cv::CV_STRING && ttype && ttype->deref().get_true_type()->is_string(); } mstch::node is_binary() { auto& ttype = const_value_->ttype(); return type_ == cv::CV_STRING && ttype && ttype->deref().get_true_type()->is_binary(); } mstch::node const_enum_type() { if (!const_value_->ttype() || type_ != cv::CV_INTEGER || !const_value_->is_enum()) { return {}; } const auto* type = const_value_->ttype()->deref().get_true_type(); if (type->is_enum()) { return generators_->type_generator_->generate(type, generators_, cache_); } return {}; } mstch::node value_for_bool() { if (auto ttype = const_value_->ttype()) { return ttype->deref().get_true_type()->is_bool(); } return false; } mstch::node value_for_floating_point() { if (auto ttype = const_value_->ttype()) { return ttype->deref().get_true_type()->is_floating_point(); } return false; } mstch::node string_value() { if (type_ != cv::CV_STRING) { return mstch::node(); } std::string string_val = const_value_->get_string(); if (string_val.find('\n') == std::string::npos) { if (string_val.find('"') == std::string::npos) { return "\"" + string_val + "\""; } if (string_val.find('\'') == std::string::npos) { return "'" + string_val + "'"; } } const auto& front = string_val.front(); const auto& back = string_val.back(); if (front != '"' && back != '"') { return "\"\"\"" + string_val + "\"\"\""; } if (front != '\'' && back != '\'') { return "'''" + string_val + "'''"; } if (front == '"') { // and back = '\'' string_val.pop_back(); // remove the last '\'' return "'''" + string_val + "'''\"'\""; } // the only possible case left: back = '"' and front = '\'' string_val.pop_back(); // remove the last '"' return "\"\"\"" + string_val + "\"\"\"'\"'"; } mstch::node list_elem_type() { if (auto ttype = const_value_->ttype()) { const auto* type = ttype->deref().get_true_type(); const t_type* elem_type = nullptr; if (type->is_list()) { elem_type = dynamic_cast<const t_list*>(type)->get_elem_type(); } else if (type->is_set()) { elem_type = dynamic_cast<const t_set*>(type)->get_elem_type(); } else { return {}; } return generators_->type_generator_->generate( elem_type, generators_, cache_, pos_); } return {}; } mstch::node value_for_set() { if (auto ttype = const_value_->ttype()) { return ttype->deref().get_true_type()->is_set(); } return false; } mstch::node map_key_type() { if (auto ttype = const_value_->ttype()) { const auto* type = ttype->deref().get_true_type(); if (type->is_map()) { return generators_->type_generator_->generate( dynamic_cast<const t_map*>(type)->get_key_type(), generators_, cache_, pos_); } } return {}; } mstch::node map_val_type() { if (auto ttype = const_value_->ttype()) { const auto* type = ttype->deref().get_true_type(); if (type->is_map()) { return generators_->type_generator_->generate( dynamic_cast<const t_map*>(type)->get_val_type(), generators_, cache_, pos_); } } return {}; } }; class type_python_generator : public type_generator { public: explicit type_python_generator(const t_program* prog) : prog_{prog} {} std::shared_ptr<mstch_base> generate( const t_type* type, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { auto true_type = type->get_true_type(); return std::make_shared<mstch_python_type>( true_type, generators, cache, pos, prog_); } protected: const t_program* prog_; }; class mstch_python_program : public mstch_program { public: mstch_python_program( const t_program* program, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos) : mstch_program{program, std::move(generators), std::move(cache), pos} { register_methods( this, { {"program:module_path", &mstch_python_program::module_path}, {"program:is_types_file?", &mstch_python_program::is_types_file}, {"program:include_namespaces", &mstch_python_program::include_namespaces}, {"program:base_library_package", &mstch_python_program::base_library_package}, {"program:root_module_prefix", &mstch_python_program::root_module_prefix}, }); gather_included_program_namespaces(); visit_types_for_services_and_interactions(); visit_types_for_objects(); visit_types_for_constants(); visit_types_for_typedefs(); visit_types_for_mixin_fields(); } mstch::node is_types_file() { return has_option("is_types_file"); } mstch::node include_namespaces() { mstch::array a; for (auto& it : include_namespaces_) { a.push_back(mstch::map{ {"included_module_path", it.second.ns}, {"has_services?", it.second.has_services}, {"has_types?", it.second.has_types}}); } return a; } mstch::node module_path() { return get_py3_namespace_with_name_and_prefix( program_, get_option("root_module_prefix")); } mstch::node base_library_package() { auto option = get_option("base_library_package"); return option.empty() ? "thrift.py3lite" : option; } mstch::node root_module_prefix() { auto prefix = get_option("root_module_prefix"); return prefix.empty() ? "" : prefix + "."; } protected: struct Namespace { std::string ns; bool has_services; bool has_types; }; void gather_included_program_namespaces() { for (const t_program* included_program : program_->get_included_programs()) { bool has_types = !(included_program->objects().empty() && included_program->enums().empty() && included_program->typedefs().empty() && included_program->consts().empty()); include_namespaces_[included_program->path()] = Namespace{ get_py3_namespace_with_name_and_prefix( included_program, get_option("root_module_prefix")), !included_program->services().empty(), has_types, }; } } void add_typedef_namespace(const t_type* type) { auto prog = type->program(); if (prog && prog != program_) { const auto& path = prog->path(); if (include_namespaces_.find(path) != include_namespaces_.end()) { return; } auto ns = Namespace(); ns.ns = get_py3_namespace_with_name_and_prefix( prog, get_option("root_module_prefix")); ns.has_services = false; ns.has_types = true; include_namespaces_[path] = std::move(ns); } } void visit_type_single_service(const t_service* service) { for (const auto& function : service->functions()) { for (const auto& field : function.get_paramlist()->fields()) { visit_type(field.get_type()); } for (const auto& field : function.get_stream_xceptions()->fields()) { visit_type(field.get_type()); } visit_type(function.get_returntype()); } } void visit_types_for_services_and_interactions() { for (const auto* service : program_->services()) { visit_type_single_service(service); } for (const auto* interaction : program_->interactions()) { visit_type_single_service(interaction); } } void visit_types_for_objects() { for (const auto& object : program_->objects()) { for (auto&& field : object->fields()) { visit_type(field.get_type()); } } } void visit_types_for_constants() { for (const auto& constant : program_->consts()) { visit_type(constant->get_type()); } } void visit_types_for_typedefs() { for (const auto typedef_def : program_->typedefs()) { visit_type(typedef_def->get_type()); } } void visit_types_for_mixin_fields() { for (const auto& strct : program_->structs()) { for (const auto& m : cpp2::get_mixins_and_members(*strct)) { visit_type(m.member->get_type()); } } } enum TypeDef { NoTypedef, HasTypedef }; void visit_type(const t_type* orig_type) { return visit_type_with_typedef(orig_type, TypeDef::NoTypedef); } void visit_type_with_typedef(const t_type* orig_type, TypeDef is_typedef) { auto true_type = orig_type->get_true_type(); if (!seen_types_.insert(true_type).second) { return; } is_typedef = is_typedef == TypeDef::HasTypedef || orig_type->is_typedef() ? TypeDef::HasTypedef : TypeDef::NoTypedef; if (is_typedef == TypeDef::HasTypedef) { add_typedef_namespace(true_type); } if (true_type->is_list()) { visit_type_with_typedef( dynamic_cast<const t_list&>(*true_type).get_elem_type(), is_typedef); } else if (true_type->is_set()) { visit_type_with_typedef( dynamic_cast<const t_set&>(*true_type).get_elem_type(), is_typedef); } else if (true_type->is_map()) { visit_type_with_typedef( dynamic_cast<const t_map&>(*true_type).get_key_type(), is_typedef); visit_type_with_typedef( dynamic_cast<const t_map&>(*true_type).get_val_type(), is_typedef); } else if (true_type->is_streamresponse()) { const t_type* resp_type = dynamic_cast<const t_stream_response&>(*true_type) .get_first_response_type(); const t_type* elem_type = dynamic_cast<const t_stream_response&>(*true_type).get_elem_type(); if (resp_type) { visit_type_with_typedef(resp_type, is_typedef); } visit_type_with_typedef(elem_type, is_typedef); } } std::map<std::string, Namespace> include_namespaces_; std::unordered_set<const t_type*> seen_types_; }; class mstch_python_field : public mstch_field { public: mstch_python_field( const t_field* field, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t index, field_generator_context const* field_context) : mstch_field( field, std::move(generators), std::move(cache), pos, index, field_context), py_name_{py3::get_py3_name(*field)} { register_methods( this, { {"field:py_name", &mstch_python_field::py_name}, }); } mstch::node py_name() { return py_name_; } private: const std::string py_name_; }; class mstch_python_struct : public mstch_struct { public: mstch_python_struct( const t_struct* strct, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos) : mstch_struct(strct, std::move(generators), std::move(cache), pos) { register_methods( this, { {"struct:fields_and_mixin_fields", &mstch_python_struct::fields_and_mixin_fields}, {"struct:exception_message?", &mstch_python_struct::has_exception_message}, {"struct:exception_message", &mstch_python_struct::exception_message}, }); } mstch::node fields_and_mixin_fields() { std::vector<t_field const*> fields = strct_->fields().copy(); for (auto m : cpp2::get_mixins_and_members(*strct_)) { fields.push_back(m.member); } return generate_fields(fields); } mstch::node has_exception_message() { return strct_->has_annotation("message"); } mstch::node exception_message() { return strct_->get_annotation("message"); } }; class mstch_python_enum : public mstch_enum { public: mstch_python_enum( const t_enum* enm, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos) : mstch_enum(enm, std::move(generators), std::move(cache), pos) { register_methods( this, { {"enum:flags?", &mstch_python_enum::has_flags}, }); } mstch::node has_flags() { return enm_->has_annotation("py3.flags"); } }; class mstch_python_enum_value : public mstch_enum_value { public: mstch_python_enum_value( const t_enum_value* enm_value, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos) : mstch_enum_value( enm_value, std::move(generators), std::move(cache), pos) { register_methods( this, { {"enum_value:py_name", &mstch_python_enum_value::py_name}, }); } mstch::node py_name() { return py3::get_py3_name(*enm_value_); } }; class program_python_generator : public program_generator { public: std::shared_ptr<mstch_base> generate( const t_program* program, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { const std::string& id = program->path(); auto it = cache->programs_.find(id); if (it != cache->programs_.end()) { return it->second; } auto r = cache->programs_.emplace( id, std::make_shared<mstch_python_program>( program, generators, cache, pos)); return r.first->second; } }; class struct_python_generator : public struct_generator { public: std::shared_ptr<mstch_base> generate( const t_struct* strct, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { return std::make_shared<mstch_python_struct>(strct, generators, cache, pos); } }; class mstch_python_function : public mstch_function { public: mstch_python_function( t_function const* function, std::shared_ptr<mstch_generators const> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION const pos) : mstch_function(function, generators, cache, pos) { register_methods( this, { {"function:args?", &mstch_python_function::has_args}, }); } mstch::node has_args() { return !function_->get_paramlist()->get_members().empty(); } protected: const std::string cppName_; }; class function_python_generator : public function_generator { public: function_python_generator() = default; ~function_python_generator() override = default; std::shared_ptr<mstch_base> generate( t_function const* function, std::shared_ptr<mstch_generators const> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { return std::make_shared<mstch_python_function>( function, generators, cache, pos); } }; class mstch_python_service : public mstch_service { public: mstch_python_service( const t_service* service, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION const pos, const t_program* prog) : mstch_service(service, generators, cache, pos), prog_{prog} { register_methods( this, { {"service:module_path", &mstch_python_service::module_path}, {"service:program_name", &mstch_python_service::program_name}, {"service:parent_service_name", &mstch_python_service::parent_service_name}, {"service:supported_functions", &mstch_python_service::supported_functions}, {"service:supported_functions?", &mstch_python_service::has_supported_functions}, {"service:external_program?", &mstch_python_service::is_external_program}, }); } mstch::node module_path() { return get_py3_namespace_with_name_and_prefix( service_->program(), get_option("root_module_prefix")); } mstch::node program_name() { return service_->program()->name(); } mstch::node parent_service_name() { return cache_->parsed_options_.at("parent_service_name"); } std::vector<t_function*> get_supported_functions() { std::vector<t_function*> funcs; for (auto func : service_->get_functions()) { if (is_func_supported(func)) { funcs.push_back(func); } } return funcs; } mstch::node supported_functions() { return generate_functions(get_supported_functions()); } mstch::node has_supported_functions() { return !get_supported_functions().empty(); } mstch::node is_external_program() { return prog_ != service_->program(); } protected: const t_program* prog_; }; class service_python_generator : public service_generator { public: explicit service_python_generator(const t_program* prog) : prog_{prog} {} std::shared_ptr<mstch_base> generate( const t_service* service, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { return std::make_shared<mstch_python_service>( service, generators, cache, pos, prog_); } protected: const t_program* prog_; }; class field_python_generator : public field_generator { public: std::shared_ptr<mstch_base> generate( const t_field* field, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t index, field_generator_context const* field_context) const override { return std::make_shared<mstch_python_field>( field, generators, cache, pos, index, field_context); } }; class enum_python_generator : public enum_generator { public: std::shared_ptr<mstch_base> generate( const t_enum* enm, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { return std::make_shared<mstch_python_enum>(enm, generators, cache, pos); } }; class enum_value_python_generator : public enum_value_generator { public: std::shared_ptr<mstch_base> generate( const t_enum_value* enm_value, std::shared_ptr<const mstch_generators> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t /*index*/) const override { return std::make_shared<mstch_python_enum_value>( enm_value, generators, cache, pos); } }; class const_value_python_generator : public const_value_generator { public: const_value_python_generator() = default; ~const_value_python_generator() override = default; std::shared_ptr<mstch_base> generate( t_const_value const* const_value, std::shared_ptr<mstch_generators const> generators, std::shared_ptr<mstch_cache> cache, ELEMENT_POSITION pos, int32_t index, t_const const* current_const, t_type const* expected_type) const override { return std::make_shared<mstch_python_const_value>( const_value, current_const, expected_type, generators, cache, pos, index); } }; /** * Generator-specific validator that enforces that reserved key is * not used as namespace field name. */ class no_reserved_key_in_namespace_validator : virtual public validator { public: using validator::visit; bool visit(t_program* const prog) override { set_program(prog); validate(prog); return true; } private: void validate(t_program* const prog) { const auto& py3_namespace = prog->get_namespace("py3"); if (py3_namespace.empty()) { return; } std::vector<std::string> namespace_tokens = split_namespace(py3_namespace); for (const auto& field_name : namespace_tokens) { if (get_python_reserved_names().find(field_name) != get_python_reserved_names().end()) { std::ostringstream ss; ss << "Namespace '" << py3_namespace << "' contains reserved keyword '" << field_name << "'"; add_error(boost::none, ss.str()); } } std::string filepath_delimiters("\\/."); std::vector<std::string> fields; boost::split(fields, prog->path(), boost::is_any_of(filepath_delimiters)); for (const auto& field : fields) { if (field == "include") { std::ostringstream ss; ss << "Path '" << prog->path() << "' contains reserved keyword 'include'"; add_error(boost::none, ss.str()); } } } }; /** * Generator-specific validator that enforces "name" and "value" is not used * as enum member or union field names (thrift-py3) */ class enum_member_union_field_names_validator : virtual public validator { public: using validator::visit; bool visit(t_enum* enm) override { for (const t_enum_value* ev : enm->get_enum_values()) { validate(ev, ev->get_name()); } return true; } bool visit(t_struct* s) override { if (!s->is_union()) { return false; } for (const t_field& f : s->fields()) { validate(&f, f.name()); } return true; } private: void validate(const t_named* node, const std::string& name) { const auto& pyname = node->get_annotation("py3.name", &name); if (pyname == "name" || pyname == "value") { std::ostringstream ss; ss << "'" << pyname << "' should not be used as an enum/union field name in thrift-py3. " << "Use a different name or annotate the field with `(py3.name=\"<new_py_name>\")`"; add_error(node->get_lineno(), ss.str()); } } }; class t_mstch_python_generator : public t_mstch_generator { public: t_mstch_python_generator( t_program* program, t_generation_context context, const std::map<std::string, std::string>& parsed_options, const std::string& /* option_string unused */) : t_mstch_generator( program, std::move(context), "python", parsed_options), generate_root_path_{package_to_path()} { out_dir_base_ = "gen-python"; auto include_prefix = get_option("include_prefix"); if (!include_prefix.empty()) { program->set_include_prefix(std::move(include_prefix)); } } void generate_program() override { set_mstch_generators(); generate_types(); generate_metadata(); generate_clients(); generate_services(); } void fill_validator_list(validator_list& vl) const override { vl.add<no_reserved_key_in_namespace_validator>(); vl.add<enum_member_union_field_names_validator>(); } enum TypesFile { IsTypesFile, NotTypesFile }; protected: bool should_resolve_typedefs() const override { return true; } void set_mstch_generators(); void generate_file( const std::string& file, TypesFile is_types_file, const boost::filesystem::path& base); void set_types_file(bool val); void generate_types(); void generate_metadata(); void generate_clients(); void generate_services(); boost::filesystem::path package_to_path(); const boost::filesystem::path generate_root_path_; }; } // namespace void t_mstch_python_generator::set_mstch_generators() { generators_->set_program_generator( std::make_unique<program_python_generator>()); generators_->set_struct_generator( std::make_unique<struct_python_generator>()); generators_->set_function_generator( std::make_unique<function_python_generator>()); generators_->set_service_generator( std::make_unique<service_python_generator>(get_program())); generators_->set_field_generator(std::make_unique<field_python_generator>()); generators_->set_enum_generator(std::make_unique<enum_python_generator>()); generators_->set_enum_value_generator( std::make_unique<enum_value_python_generator>()); generators_->set_const_value_generator( std::make_unique<const_value_python_generator>()); generators_->set_type_generator( std::make_unique<type_python_generator>(get_program())); } boost::filesystem::path t_mstch_python_generator::package_to_path() { auto package = get_program()->get_namespace("py3"); return boost::algorithm::replace_all_copy(package, ".", "/"); } void t_mstch_python_generator::generate_file( const std::string& file, TypesFile is_types_file, const boost::filesystem::path& base = {}) { auto program = get_program(); const auto& name = program->name(); if (is_types_file == IsTypesFile) { cache_->parsed_options_["is_types_file"] = ""; } else { cache_->parsed_options_.erase("is_types_file"); } auto node_ptr = generators_->program_generator_->generate(program, generators_, cache_); render_to_file(node_ptr, file, base / name / file); } void t_mstch_python_generator::generate_types() { generate_file("lite_types.py", IsTypesFile, generate_root_path_); generate_file("lite_types.pyi", IsTypesFile, generate_root_path_); generate_file("thrift_types.py", IsTypesFile, generate_root_path_); generate_file("thrift_types.pyi", IsTypesFile, generate_root_path_); } void t_mstch_python_generator::generate_metadata() { generate_file("lite_metadata.py", IsTypesFile, generate_root_path_); generate_file("thrift_metadata.py", IsTypesFile, generate_root_path_); } void t_mstch_python_generator::generate_clients() { if (get_program()->services().empty()) { // There is no need to generate empty / broken code for non existent // services. return; } generate_file("lite_clients.py", NotTypesFile, generate_root_path_); generate_file("thrift_clients.py", NotTypesFile, generate_root_path_); } void t_mstch_python_generator::generate_services() { if (get_program()->services().empty()) { // There is no need to generate empty / broken code for non existent // services. return; } generate_file("lite_services.py", NotTypesFile, generate_root_path_); generate_file("thrift_services.py", NotTypesFile, generate_root_path_); } THRIFT_REGISTER_GENERATOR( mstch_python, "Python", " include_prefix: Use full include paths in generated files.\n"); static t_generator_factory_impl<t_mstch_python_generator> alias( "mstch_py3lite", "Py3 Lite", " include_prefix: Use full include paths in generated files.\n"); } // namespace compiler } // namespace thrift } // namespace apache