Scarab  v2.9.0
Project 8 C++ Utility Library
application_pybind.hh
Go to the documentation of this file.
1 #ifndef APPLICATION_PYBIND_HH_
2 #define APPLICATION_PYBIND_HH_
3 
4 #include "pybind11/pybind11.h"
5 #include "pybind11/functional.h"
6 #include "pybind11/stl.h"
7 
8 #include "application.hh"
9 
10 namespace scarab_pybind
11 {
12  std::list< std::string > export_application( pybind11::module& mod )
13  {
14  std::list< std::string > all_members;
15 
16  all_members.push_back( "MainApp" );
17  pybind11::class_< scarab::main_app >( mod, "MainApp", "Base class for creating CLI utilities" )
18  .def( pybind11::init< >() )
19 
20  .def( "set_callback", [](scarab::main_app* an_app, std::function< void() > a_fun){ an_app->callback( a_fun );} )
21 
22  // member variables
23  .def_property_readonly( "master_config", (scarab::param_node& (scarab::main_app::*)()) &scarab::main_app::master_config )
24  .def_property( "default_config", (scarab::param_node& (scarab::main_app::*)()) &scarab::main_app::default_config,
25  [](scarab::main_app& an_obj, scarab::param_node& a_config){ an_obj.default_config() = a_config; } )
26  .def_property_readonly( "config_filename", (std::string& (scarab::main_app::*)()) &scarab::main_app::config_filename )
27  .def_property_readonly( "global_verbosity", &scarab::main_app::get_global_verbosity )
28  .def_property_readonly( "nonoption_kw_args", (scarab::param_node& (scarab::main_app::*)()) &scarab::main_app::nonoption_kw_args )
29  .def_property_readonly( "nonoption_ord_args", (scarab::param_array& (scarab::main_app::*)()) &scarab::main_app::nonoption_ord_args )
30  .def_property_readonly( "app_options", (scarab::param_node& (scarab::main_app::*)()) &scarab::main_app::app_options )
31 
32  .def( "do_config_stage_1", &scarab::main_app::do_config_stage_1 )
33  .def( "do_config_stage_2", &scarab::main_app::do_config_stage_2 )
34  .def( "do_config_stage_3", &scarab::main_app::do_config_stage_3 )
35  .def( "do_config_stage_4", &scarab::main_app::do_config_stage_4 )
36 
37  //TODO: add_config_subcommand?
38 
39  //add_config_options... what template versions do we need?
40  .def( "add_config_flag",
41  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
42  {an_app->add_config_flag< bool >(a_name, a_addr, a_description);},
43  pybind11::arg( "flag" ),
44  pybind11::arg( "config_address" ),
45  pybind11::arg( "description" ) = "",
46  "add a CLI flag, which is toggled as a bool" )
47  .def( "add_config_counted_flag",
48  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
49  {an_app->add_config_flag< unsigned >(a_name, a_addr, a_description);},
50  pybind11::arg( "flag" ),
51  pybind11::arg( "config_address" ),
52  pybind11::arg( "description" ) = "",
53  "add a CLI flag, the config will contain a count of occurrances" )
54  .def( "add_config_string_option",
55  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
56  {an_app->add_config_option< std::string >(a_name, a_addr, a_description);},
57  pybind11::arg( "option" ),
58  pybind11::arg( "config_address" ),
59  pybind11::arg( "description" ) = "",
60  "add a single-string argument" )
61  .def( "add_config_int_option",
62  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
63  {an_app->add_config_option< int >(a_name, a_addr, a_description);},
64  pybind11::arg( "option" ),
65  pybind11::arg( "config_address" ),
66  pybind11::arg( "description" ) = "",
67  "add a single-integer argument" )
68  .def( "add_config_float_option",
69  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
70  {an_app->add_config_option< double >(a_name, a_addr, a_description);},
71  pybind11::arg( "option" ),
72  pybind11::arg( "config_address" ),
73  pybind11::arg( "description" ) = "",
74  "add a single-float argument" )
75  .def( "add_config_multi_string_option",
76  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
77  {an_app->add_config_multi_option< std::string >(a_name, a_addr, a_description);},
78  pybind11::arg( "option" ),
79  pybind11::arg( "config_address" ),
80  pybind11::arg( "description" ) = "",
81  "add a sequence of string arguments" )
82  .def( "add_config_multi_int_option",
83  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
84  {an_app->add_config_multi_option< int >(a_name, a_addr, a_description);},
85  pybind11::arg( "option" ),
86  pybind11::arg( "config_address" ),
87  pybind11::arg( "description" ) = "",
88  "add a sequence of ints arguments" )
89  .def( "add_config_multi_float_option",
90  [](scarab::main_app* an_app, std::string a_name, std::string a_addr, std::string a_description)
91  {an_app->add_config_multi_option< double >(a_name, a_addr, a_description);},
92  pybind11::arg( "option" ),
93  pybind11::arg( "config_address" ),
94  pybind11::arg( "description" ) = "",
95  "add a sequence of string arguments" )
96 
97  .def( "set_version", &scarab::main_app::set_version )
98 
99  // implement execute as a lambda, it is a macro in CLI11
100  .def( "execute",
101  [](scarab::main_app& an_app, std::list< std::string > args )
102  {
103  //TODO: this feels... super ugly, also how do I deal with errors/return codes?
104  const char* argv[args.size()];
105  std::list< std::string >::iterator an_arg = args.begin();
106  for (unsigned i_arg=0; i_arg<args.size(); ++i_arg)
107  {
108  argv[i_arg] = an_arg->c_str();
109  ++an_arg;
110  }
111  // CLI11_PARSE returns an integer in the event of an error, the are meant to be
112  // valid shell return codes, so 0 is success
113  CLI11_PARSE( an_app, args.size(), argv );
114  return 0;
115  },
116  "parse arguments and execute the application" )
117 
118  ;
119 
120  return all_members;
121  }
122 } /* namespace scarab_pybind */
123 #endif /* APPLICATION_PYBIND_HH_ */
class_ & def_property_readonly(const char *name, const Getter &fget, const Extra &...extra)
Uses return_value_policy::reference_internal by default.
Definition: pybind11.h:1219
void set_version(scarab::version_semantic_ptr_t a_ver)
Definition: application.cc:73
Wrapper for Python extension modules.
Definition: pybind11.h:789
virtual void do_config_stage_4()
Load the application-specific options.
Definition: application.cc:145
virtual void do_config_stage_1()
Load default values.
Definition: application.cc:106
std::list< std::string > export_application(pybind11::module &mod)
virtual void do_config_stage_2()
Load the config file.
Definition: application.cc:114
CLI::Option * add_config_flag(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Definition: application.hh:329
App * callback(std::function< void()> app_callback)
Definition: CLI11.hpp:3920
CLI::Option * add_config_option(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Add an option that gets automatically added to the master config of a main_app.
Definition: application.hh:305
CLI::Option * add_config_multi_option(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Add an option that gets automatically added to the master config of a main_app.
Definition: application.hh:317
#define CLI11_PARSE(app, argc, argv)
Definition: CLI11.hpp:3669
Primary application class.
Definition: application.hh:253
virtual void do_config_stage_3()
Load the directly-addressed non-option arguments.
Definition: application.cc:137
bool typename Extra class_ & def(const char *name_, Func &&f, const Extra &... extra)
Definition: pybind11.h:1110