{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Names and types translation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are numerous names and types translation options in the [options](https://github.com/pthom/litgen/blob/main/src/litgen/options.py) file.\n", "\n", "Below is a relevant extract from the options:\n", "\n", "```python\n", " ################################################################################\n", " # \n", " ################################################################################\n", " # Convert variables, functions and namespaces names to snake_case (class, structs, and enums names are always preserved)\n", " python_convert_to_snake_case: bool = True\n", " # List of code replacements when going from C++ to Python\n", " # Notes:\n", " # - by default, type_replacements is prefilled with standard_type_replacements()\n", " # type_replacements will be applied to all types (including class and enum names)\n", " # - by default, value_replacements is prefilled with standard_value_replacements()\n", " # - by default, comments_replacements is prefilled with standard_comments_replacements()\n", " # - by default, the others are empty\n", " # - type_replacements, var_names_replacements and function_names_replacements enable you\n", " # to modify the outputted python code\n", " type_replacements: RegexReplacementList # = cpp_to_python.standard_type_replacements() by default\n", " var_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)\n", " namespace_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)\n", " function_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)\n", " value_replacements: RegexReplacementList # = cpp_to_python.standard_value_replacements() by default\n", " comments_replacements: RegexReplacementList # = cpp_to_python.standard_comment_replacements() by default\n", " macro_name_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Types replacements\n", "\n", "`options.type_replacements` enables to change the way some types are exported.\n", "\n", "Let's take an example with some C++ code. \n", "\n", "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]`. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "cpp_code = \"\"\"\n", " MyPair GetMinMax(std::vector& values);\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we convert it, we see that `std::vector` is correctly interpreted as a `List[int]`, however `MyPair` is not." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
    MyPair<int, int> GetMinMax(std::vector<int>& values);\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
def get_min_max(values: List[int]) -> MyPair<int, int>:\n",
       "    pass\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
m.def("get_min_max",\n",
       "    GetMinMax, py::arg("values"));\n",
       "
\n", "\n", "
\n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import litgen\n", "from litgen.demo import litgen_demo\n", "\n", "options = litgen.LitgenOptions()\n", "litgen_demo.demo(options, cpp_code)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to account for `MyPair`, we need to add replacements to `options.type_replacements`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
    MyPair<int, int> GetMinMax(std::vector<int>& values);\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
def get_min_max(values: List[int]) -> Tuple[int, int]:\n",
       "    pass\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
m.def("get_min_max",\n",
       "    GetMinMax, py::arg("values"));\n",
       "
\n", "\n", "
\n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "options = litgen.LitgenOptions()\n", "options.type_replacements.add_last_replacement(\n", " r\"MyPair<(.*),\\s*(.*)>\", # this is a regex, with 2 captures\n", " r\"Tuple[\\1, \\2]\" # and this is the replacement\n", ")\n", "litgen_demo.demo(options, cpp_code)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: by default `options.type_replacements` already contains standard replacements regexes. See `standard_type_replacements()` inside packages/litgen/internal/cpp_to_python.py." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Convert to snake case\n", "\n", "The code below:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "cpp_code = \"\"\"\n", "namespace MyNamespace\n", "{\n", " struct MyClass\n", " {\n", " int AddNumber(int a, int b);\n", "\n", " int MultiplierRatio = 4;\n", " };\n", "}\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default, the bindings will convert CamelCase to snake_case for functions, variables and namespaces:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
namespace MyNamespace\n",
       "{\n",
       "    struct MyClass\n",
       "    {\n",
       "        int AddNumber(int a, int b);\n",
       "\n",
       "        int MultiplierRatio = 4;\n",
       "    };\n",
       "}\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
# <submodule my_namespace>\n",
       "class my_namespace:  # Proxy class that introduces typings for the *submodule* my_namespace\n",
       "    pass  # (This corresponds to a C++ namespace. All method are static!)\n",
       "    class MyClass:\n",
       "        def add_number(self, a: int, b: int) -> int:\n",
       "            pass\n",
       "\n",
       "        multiplier_ratio: int = 4\n",
       "        def __init__(self, multiplier_ratio: int = 4) -> None:\n",
       "            """Auto-generated default constructor with named params"""\n",
       "            pass\n",
       "\n",
       "# </submodule my_namespace>\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
{ // <namespace MyNamespace>\n",
       "    py::module_ pyNsMyNamespace = m.def_submodule("my_namespace", "");\n",
       "    auto pyNsMyNamespace_ClassMyClass =\n",
       "        py::class_<MyNamespace::MyClass>\n",
       "            (pyNsMyNamespace, "MyClass", "")\n",
       "        .def(py::init<>([](\n",
       "        int MultiplierRatio = 4)\n",
       "        {\n",
       "            auto r = std::make_unique<MyNamespace::MyClass>();\n",
       "            r->MultiplierRatio = MultiplierRatio;\n",
       "            return r;\n",
       "        })\n",
       "        , py::arg("multiplier_ratio") = 4\n",
       "        )\n",
       "        .def("add_number",\n",
       "            &MyNamespace::MyClass::AddNumber, py::arg("a"), py::arg("b"))\n",
       "        .def_readwrite("multiplier_ratio", &MyNamespace::MyClass::MultiplierRatio, "")\n",
       "        ;\n",
       "} // </namespace MyNamespace>\n",
       "
\n", "\n", "
\n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import litgen\n", "\n", "options = litgen.LitgenOptions()\n", "litgen_demo.demo(options, cpp_code)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, you can set `options.python_convert_to_snake_case = False` to disable this." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
namespace MyNamespace\n",
       "{\n",
       "    struct MyClass\n",
       "    {\n",
       "        int AddNumber(int a, int b);\n",
       "\n",
       "        int MultiplierRatio = 4;\n",
       "    };\n",
       "}\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", " \n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
# <submodule MyNamespace>\n",
       "class MyNamespace:  # Proxy class that introduces typings for the *submodule* MyNamespace\n",
       "    pass  # (This corresponds to a C++ namespace. All method are static!)\n",
       "    class MyClass:\n",
       "        def AddNumber(self, a: int, b: int) -> int:\n",
       "            pass\n",
       "\n",
       "        MultiplierRatio: int = 4\n",
       "        def __init__(self, MultiplierRatio: int = 4) -> None:\n",
       "            """Auto-generated default constructor with named params"""\n",
       "            pass\n",
       "\n",
       "# </submodule MyNamespace>\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
{ // <namespace MyNamespace>\n",
       "    py::module_ pyNsMyNamespace = m.def_submodule("MyNamespace", "");\n",
       "    auto pyNsMyNamespace_ClassMyClass =\n",
       "        py::class_<MyNamespace::MyClass>\n",
       "            (pyNsMyNamespace, "MyClass", "")\n",
       "        .def(py::init<>([](\n",
       "        int MultiplierRatio = 4)\n",
       "        {\n",
       "            auto r = std::make_unique<MyNamespace::MyClass>();\n",
       "            r->MultiplierRatio = MultiplierRatio;\n",
       "            return r;\n",
       "        })\n",
       "        , py::arg("MultiplierRatio") = 4\n",
       "        )\n",
       "        .def("AddNumber",\n",
       "            &MyNamespace::MyClass::AddNumber, py::arg("a"), py::arg("b"))\n",
       "        .def_readwrite("MultiplierRatio", &MyNamespace::MyClass::MultiplierRatio, "")\n",
       "        ;\n",
       "} // </namespace MyNamespace>\n",
       "
\n", "\n", "
\n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "options.python_convert_to_snake_case = False\n", "litgen_demo.demo(options, cpp_code)" ] } ], "metadata": { "kernelspec": { "display_name": "venv311", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 2 }