Names and types translation#
There are numerous names and types translation options in the options file.
Below is a relevant extract from the options:
################################################################################
# <names translation from C++ to python>
################################################################################
# Convert variables, functions and namespaces names to snake_case (class, structs, and enums names are always preserved)
python_convert_to_snake_case: bool = True
# List of code replacements when going from C++ to Python
# Notes:
# - by default, type_replacements is prefilled with standard_type_replacements()
# type_replacements will be applied to all types (including class and enum names)
# - by default, value_replacements is prefilled with standard_value_replacements()
# - by default, comments_replacements is prefilled with standard_comments_replacements()
# - by default, the others are empty
# - type_replacements, var_names_replacements and function_names_replacements enable you
# to modify the outputted python code
type_replacements: RegexReplacementList # = cpp_to_python.standard_type_replacements() by default
var_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
namespace_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
function_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
value_replacements: RegexReplacementList # = cpp_to_python.standard_value_replacements() by default
comments_replacements: RegexReplacementList # = cpp_to_python.standard_comment_replacements() by default
macro_name_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
Types replacements#
options.type_replacements
enables to change the way some types are exported.
Let’s take an example with some C++ code.
In the example below, MyPair
is a template class that should behave like a std::pair, and should be presented as a python Tuple[int, int]
.
cpp_code = """
MyPair<int, int> GetMinMax(std::vector<int>& values);
"""
If we convert it, we see that std::vector<int>
is correctly interpreted as a List[int]
, however MyPair<int, int>
is not.
import litgen
from litgen.demo import litgen_demo
options = litgen.LitgenOptions()
litgen_demo.demo(options, cpp_code)
MyPair<int, int> GetMinMax(std::vector<int>& values);
def get_min_max(values: List[int]) -> MyPair[int, int]:
pass
m.def("get_min_max",
GetMinMax, py::arg("values"));
m.def("get_min_max",
GetMinMax, nb::arg("values"));
In order to account for MyPair<int, int>
, we need to add replacements to options.type_replacements
:
options = litgen.LitgenOptions()
options.type_replacements.add_last_replacement(
r"MyPair<(.*),\s*(.*)>", # this is a regex, with 2 captures
r"Tuple[\1, \2]" # and this is the replacement
)
litgen_demo.demo(options, cpp_code)
MyPair<int, int> GetMinMax(std::vector<int>& values);
def get_min_max(values: List[int]) -> Tuple[int, int]:
pass
m.def("get_min_max",
GetMinMax, py::arg("values"));
m.def("get_min_max",
GetMinMax, nb::arg("values"));
Note: by default options.type_replacements
already contains standard replacements regexes. See standard_type_replacements()
inside packages/litgen/internal/cpp_to_python.py.
Convert to snake case#
The code below:
cpp_code = """
namespace MyNamespace
{
struct MyClass
{
int AddNumber(int a, int b);
int MultiplierRatio = 4;
};
}
"""
By default, the bindings will convert CamelCase to snake_case for functions, variables and namespaces:
import litgen
options = litgen.LitgenOptions()
litgen_demo.demo(options, cpp_code)
namespace MyNamespace
{
struct MyClass
{
int AddNumber(int a, int b);
int MultiplierRatio = 4;
};
}
# <submodule my_namespace>
class my_namespace: # Proxy class that introduces typings for the *submodule* my_namespace
pass # (This corresponds to a C++ namespace. All method are static!)
class MyClass:
def add_number(self, a: int, b: int) -> int:
pass
multiplier_ratio: int = 4
def __init__(self, multiplier_ratio: int = 4) -> None:
"""Auto-generated default constructor with named params"""
pass
# </submodule my_namespace>
{ // <namespace MyNamespace>
py::module_ pyNsMyNamespace = m.def_submodule("my_namespace", "");
auto pyNsMyNamespace_ClassMyClass =
py::class_<MyNamespace::MyClass>
(pyNsMyNamespace, "MyClass", "")
.def(py::init<>([](
int MultiplierRatio = 4)
{
auto r = std::make_unique<MyNamespace::MyClass>();
r->MultiplierRatio = MultiplierRatio;
return r;
})
, py::arg("multiplier_ratio") = 4
)
.def("add_number",
&MyNamespace::MyClass::AddNumber, py::arg("a"), py::arg("b"))
.def_readwrite("multiplier_ratio", &MyNamespace::MyClass::MultiplierRatio, "")
;
} // </namespace MyNamespace>
{ // <namespace MyNamespace>
nb::module_ pyNsMyNamespace = m.def_submodule("my_namespace", "");
auto pyNsMyNamespace_ClassMyClass =
nb::class_<MyNamespace::MyClass>
(pyNsMyNamespace, "MyClass", "")
.def("__init__", [](MyNamespace::MyClass * self, int MultiplierRatio = 4)
{
new (self) MyNamespace::MyClass(); // placement new
auto r = self;
r->MultiplierRatio = MultiplierRatio;
},
nb::arg("multiplier_ratio") = 4
)
.def("add_number",
&MyNamespace::MyClass::AddNumber, nb::arg("a"), nb::arg("b"))
.def_rw("multiplier_ratio", &MyNamespace::MyClass::MultiplierRatio, "")
;
} // </namespace MyNamespace>
However, you can set options.python_convert_to_snake_case = False
to disable this.
options.python_convert_to_snake_case = False
litgen_demo.demo(options, cpp_code)
namespace MyNamespace
{
struct MyClass
{
int AddNumber(int a, int b);
int MultiplierRatio = 4;
};
}
# <submodule MyNamespace>
class MyNamespace: # Proxy class that introduces typings for the *submodule* MyNamespace
pass # (This corresponds to a C++ namespace. All method are static!)
class MyClass:
def AddNumber(self, a: int, b: int) -> int:
pass
MultiplierRatio: int = 4
def __init__(self, MultiplierRatio: int = 4) -> None:
"""Auto-generated default constructor with named params"""
pass
# </submodule MyNamespace>
{ // <namespace MyNamespace>
py::module_ pyNsMyNamespace = m.def_submodule("MyNamespace", "");
auto pyNsMyNamespace_ClassMyClass =
py::class_<MyNamespace::MyClass>
(pyNsMyNamespace, "MyClass", "")
.def(py::init<>([](
int MultiplierRatio = 4)
{
auto r = std::make_unique<MyNamespace::MyClass>();
r->MultiplierRatio = MultiplierRatio;
return r;
})
, py::arg("MultiplierRatio") = 4
)
.def("AddNumber",
&MyNamespace::MyClass::AddNumber, py::arg("a"), py::arg("b"))
.def_readwrite("MultiplierRatio", &MyNamespace::MyClass::MultiplierRatio, "")
;
} // </namespace MyNamespace>
{ // <namespace MyNamespace>
nb::module_ pyNsMyNamespace = m.def_submodule("MyNamespace", "");
auto pyNsMyNamespace_ClassMyClass =
nb::class_<MyNamespace::MyClass>
(pyNsMyNamespace, "MyClass", "")
.def("__init__", [](MyNamespace::MyClass * self, int MultiplierRatio = 4)
{
new (self) MyNamespace::MyClass(); // placement new
auto r = self;
r->MultiplierRatio = MultiplierRatio;
},
nb::arg("MultiplierRatio") = 4
)
.def("AddNumber",
&MyNamespace::MyClass::AddNumber, nb::arg("a"), nb::arg("b"))
.def_rw("MultiplierRatio", &MyNamespace::MyClass::MultiplierRatio, "")
;
} // </namespace MyNamespace>