{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# litgen options\n", "\n", "litgen uses numerous options which can be found here: [litgen/options.py](https://github.com/pthom/litgen/blob/main/src/litgen/options.py).\n", "\n", "\n", "## Note about regexes\n", "Many options use regexes: see the note about their usage in the [options.py](https://github.com/pthom/litgen/blob/main/src/litgen/options.py) file:\n", "\n", "\n", "regexes can support several alternatives: separate them by \"|\". \n", "\n", "For example, in order to match an exact function name (`YourFunctionName`), as well as functions ending with `_private`, use a regex like this:\n", "\n", " r\"^YourFunctionName$|_private$\",\n", "\n", "_Tips:_\n", "- If a regex string is empty, it will not match anything (this is specific to litgen)\n", "- To match everything, use r\".*\"\n", "- It is advised to prefix your regex strings with \"r\" (in order to use raw strings)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## litgen main options\n", "\n", "Below, we show the content of litgen/options.py:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
from __future__ import annotations\n",
       "\n",
       "from typing import Any, Callable, List\n",
       "\n",
       "from codemanip import code_utils\n",
       "from codemanip.code_replacements import RegexReplacementList\n",
       "\n",
       "from srcmlcpp import SrcmlcppOptions\n",
       "\n",
       "from litgen.internal.template_options import TemplateFunctionsOptions, TemplateClassOptions\n",
       "from litgen.internal.class_iterable_info import ClassIterablesInfos\n",
       "\n",
       "\n",
       "class Blah:\n",
       "    values: List[int] = []\n",
       "\n",
       "\n",
       "class LitgenOptions:\n",
       "    """Numerous options to configure litgen code generation.\n",
       "\n",
       "    (include / excludes, indentation, c++ to python translation settings, function parameters\n",
       "    adaptations, etc.)"""\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Note about regexes below:\n",
       "    # =========================\n",
       "    # - regexes can support several alternatives: separate them by "|"\n",
       "    # For example, in order to match an exact function name, as well as functions ending with "_private",\n",
       "    # use a regex like this:\n",
       "    #         r"^YourFunctionName$|_private$",\n",
       "    # - If a regex string is empty, it will not match anything\n",
       "    # - To match everything, use r".*"\n",
       "    # - It is advised to prefix your regex strings with "r" (in order to use raw strings)\n",
       "    # ------------------------------------------------------------------------------\n",
       "\n",
       "    ################################################################################\n",
       "    #    <srcmlcpp options>\n",
       "    ################################################################################\n",
       "    # There are interesting options to set in SrcmlcppOptions (see srcmlcpp/srcmlcpp_options.py)\n",
       "    #\n",
       "    # Notably:\n",
       "    # * fill srcmlcpp_options.functions_api_prefixes: the prefix(es) that denotes exported dll functions\n",
       "    # * also set LitgenOptions.fn_exclude_non_api=True if you want to exclude non api functions and methods\n",
       "    srcmlcpp_options: SrcmlcppOptions\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Layout settings for the generated python stub code>\n",
       "    ################################################################################\n",
       "    #    <show the original location and or signature of elements as a comment>\n",
       "    original_location_flag_show = False\n",
       "    # if showing location, how many parent folders shall be shown\n",
       "    # (if -1, show the full path)\n",
       "    original_location_nb_parent_folders = 0\n",
       "    # If True, the complete C++ original signature will be show as a comment in the python stub (pyi)\n",
       "    original_signature_flag_show = False\n",
       "    # Size of an indentation in the python stubs\n",
       "    python_indent_size = 4\n",
       "    python_ident_with_tabs: bool = False\n",
       "    # Insert as many empty lines in the python stub as found in the header file, keep comments layout, etc.\n",
       "    python_reproduce_cpp_layout: bool = True\n",
       "    # The generated code will try to adhere to this max length (if negative, this is ignored)\n",
       "    python_max_line_length = 88\n",
       "    # Strip (remove) empty comment lines\n",
       "    python_strip_empty_comment_lines: bool = False\n",
       "    # Run black formatter\n",
       "    python_run_black_formatter: bool = False\n",
       "    python_black_formatter_line_length: int = 88\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Layout settings for the C++ generated pydef code>\n",
       "    ################################################################################\n",
       "    # Spacing option in C++ code\n",
       "    cpp_indent_size: int = 4\n",
       "    cpp_indent_with_tabs: bool = False\n",
       "\n",
       "    ################################################################################\n",
       "    #    <names translation from C++ to python>\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",
       "\n",
       "    ################################################################################\n",
       "    #    <functions and method adaptations>\n",
       "    ################################################################################\n",
       "\n",
       "    # Exclude certain functions and methods by a regex on their name\n",
       "    fn_exclude_by_name__regex: str = ""\n",
       "\n",
       "    # Exclude certain functions and methods by a regex on any of their parameter type and/or return type\n",
       "    # (those should be decorated type)\n",
       "    # For example:\n",
       "    #     options.fn_exclude_by_param_type__regex = "^char\\s*$|^unsigned\\s+char$|Callback$"\n",
       "    # would exclude all functions having params of type "char *", "unsigned char", "xxxCallback"\n",
       "    #\n",
       "    # Note: this is distinct from `fn_params_exclude_types__regex` which removes params\n",
       "    # from the function signature, but not the function itself.\n",
       "    fn_exclude_by_param_type__regex: str = ""\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Exclude some params by name or type\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Remove some params from the python published interface. A param can only be removed if it has a default value\n",
       "    # in the C++ signature\n",
       "    fn_params_exclude_names__regex: str = ""\n",
       "    fn_params_exclude_types__regex: str = ""\n",
       "\n",
       "    # fn_exclude_non_api:\n",
       "    # if srcmlcpp_options.functions_api_prefixes is filled, and fn_exclude_non_api=True,\n",
       "    # then only functions with an api marker will be exported.\n",
       "    fn_exclude_non_api: bool = True\n",
       "    # fn_non_api_comment:\n",
       "    # if fn_exclude_non_api is False, a comment can be added to non api functions in the stub file\n",
       "    fn_non_api_comment: str = "(private API)"\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Templated functions options\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Template function must be instantiated for the desired types.\n",
       "    # See https://pybind11.readthedocs.io/en/stable/advanced/functions.html#binding-functions-with-template-parameters\n",
       "    #\n",
       "    # fn_template_options:\n",
       "    #    of type Dict[ TemplatedFunctionNameRegexStr (aka str), List[CppTypeName] ]\n",
       "    #\n",
       "    # For example,\n",
       "    # 1. This line:\n",
       "    #        options.fn_template_options.add_specialization(r"template^", ["int", double"])\n",
       "    #    would instantiate all template functions whose name end with "template" with "int" and "double"\n",
       "    # 2. This line:\n",
       "    #        options.fn_template_options.add_specialization(r".*", ["int", float"])\n",
       "    #    would instantiate all template functions (whatever their name) with "int" and "float"\n",
       "    # 3. This line:\n",
       "    #        options.fn_template_options.add_ignore(r".*")\n",
       "    #    would ignore all template functions (they will not be exported)\n",
       "    fn_template_options: TemplateFunctionsOptions\n",
       "    # if fn_template_decorate_in_stub is True, then there will be some\n",
       "    # decorative comments in the stub file, in order to visually group\n",
       "    # the generated functions together\n",
       "    fn_template_decorate_in_stub: bool = True\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Vectorize functions options\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Numeric functions (i.e. function accepting and returning only numeric params or py::array), can be vectorized\n",
       "    # i.e. they will accept numpy arrays as an input.\n",
       "    # See https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html#vectorizing-functions\n",
       "    # and https://github.com/pybind/pybind11/blob/master/tests/test_numpy_vectorize.cpp\n",
       "    #\n",
       "    # * fn_vectorize__regex and fn_namespace_vectorize__regex contain a regexes\n",
       "    # on functions names + namespace names for which this transformation will be applied.\n",
       "    #\n",
       "    # For example, to vectorize all function of the namespace MathFunctions, apply these options:\n",
       "    #     options.fn_namespace_vectorize__regex: str = r"MathFunctions^$"\n",
       "    #     options.fn_vectorize__regex = r".*"\n",
       "    #\n",
       "    # * fn_vectorize_prefix and fn_vectorize_suffix will be added to the vectorized functions names\n",
       "    #   (they can be empty, in which case the vectorized function will be a usable overload with the same name)\n",
       "    fn_vectorize__regex: str = r""\n",
       "    fn_namespace_vectorize__regex: str = r""\n",
       "    fn_vectorize_prefix: str = ""\n",
       "    fn_vectorize_suffix: str = ""\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Return policy\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Force the function that match those regexes to use `pybind11::return_value_policy::reference`\n",
       "    #\n",
       "    # Note:\n",
       "    #    you can also write "// py::return_value_policy::reference" as an end of line comment after the function.\n",
       "    #    See packages/litgen/integration_tests/mylib/include/mylib/return_value_policy_test.h as an example\n",
       "    fn_return_force_policy_reference_for_pointers__regex: str = ""\n",
       "    fn_return_force_policy_reference_for_references__regex: str = ""\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Force overload\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Force using py::overload for functions that matches these regexes\n",
       "    fn_force_overload__regex: str = ""\n",
       "    # Force using a lambda for functions that matches these regexes\n",
       "    # (useful when pybind11 is confused and gives error like\n",
       "    #     error: no matching function for call to object of type 'const detail::overload_cast_impl<...>'\n",
       "    fn_force_lambda__regex: str = ""\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # C style buffers to py::array\n",
       "    # ------------------------------------------------------------------------------\n",
       "    #\n",
       "    # Signatures with a C buffer like this:\n",
       "    #       MY_API inline void add_inside_array(uint8_t* array, size_t array_size, uint8_t number_to_add)\n",
       "    # may be transformed to:\n",
       "    #       void add_inside_array(py::array & array, uint8_t number_to_add)              (c++ bound signature)\n",
       "    #       def add_inside_array(array: numpy.ndarray, number_to_add: int) -> None       (python)\n",
       "    #\n",
       "    # It also works for templated buffers:\n",
       "    #       MY_API template<typename T> void mul_inside_array(T* array, size_t array_size, double factor)\n",
       "    # will be transformed to:\n",
       "    #       void mul_inside_array(py::array & array, double factor)                      (c++ bound signature)\n",
       "    #       def mul_inside_array(array: numpy.ndarray, factor: float) -> None            (python)\n",
       "    # (and factor will be down-casted to the target type)\n",
       "    #\n",
       "    # fn_params_buffer_replace_by_array_regexes contains a regex on functions names\n",
       "    # for which this transformation will be applied.\n",
       "    # Set it to r".*" to apply this to all functions, set it to "" to disable it\n",
       "    #\n",
       "    fn_params_replace_buffer_by_array__regex: str = r""\n",
       "\n",
       "    # fn_params_buffer_types: list of numeric types that are considered as possible buffers.\n",
       "    # You can customize this list in your own options by removing items from it,\n",
       "    # but you *cannot* add new types or new synonyms (typedef for examples); since the conversion between\n",
       "    # py::array and native relies on these *exact* names!\n",
       "    #\n",
       "    # By default, fn_params_buffer_types will contain those types:\n",
       "    fn_params_buffer_types: str = code_utils.join_string_by_pipe_char(\n",
       "        [\n",
       "            "uint8_t",\n",
       "            "int8_t",\n",
       "            "uint16_t",\n",
       "            "int16_t",\n",
       "            "uint32_t",\n",
       "            "int32_t",\n",
       "            "np_uint_l",  # Platform dependent: "uint64_t" on *nixes, "uint32_t" on windows\n",
       "            "np_int_l",  # Platform dependent: "int64_t" on *nixes, "int32_t" on windows\n",
       "            "float",\n",
       "            "double",\n",
       "            "long double",\n",
       "            "long long",\n",
       "        ]\n",
       "    )\n",
       "\n",
       "    # fn_params_buffer_template_types: list of templated names that are considered as possible templated buffers\n",
       "    # By default, only template<typename T> or template<typename NumericType> are accepted\n",
       "    fn_params_buffer_template_types: str = code_utils.join_string_by_pipe_char(["T", "NumericType"])\n",
       "\n",
       "    # fn_params_buffer_size_names__regex: possible names for the size of the buffer\n",
       "    # = ["nb", "size", "count", "total", "n"] by default\n",
       "    fn_params_buffer_size_names__regex: str = code_utils.join_string_by_pipe_char(\n",
       "        [\n",
       "            code_utils.make_regex_var_name_contains_word("nb"),\n",
       "            code_utils.make_regex_var_name_contains_word("size"),\n",
       "            code_utils.make_regex_var_name_contains_word("count"),\n",
       "            code_utils.make_regex_var_name_contains_word("total"),\n",
       "            code_utils.make_regex_var_name_contains_word("n"),\n",
       "        ]\n",
       "    )\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # C style arrays functions and methods parameters\n",
       "    # ------------------------------------------------------------------------------\n",
       "    #\n",
       "    # Signatures like\n",
       "    #       void foo_const(const int input[2])\n",
       "    # may be transformed to:\n",
       "    #       void foo_const(const std::array<int, 2>& input)    (c++ bound signature)\n",
       "    #       def foo_const(input: List[int]) -> None:           (python)\n",
       "    # fn_params_replace_c_array_const_by_std_array__regex contains a list of regexes on functions names\n",
       "    # for which this transformation will be applied.\n",
       "    # Set it to r".*" to apply this to all functions, set it to "" to disable it\n",
       "    fn_params_replace_c_array_const_by_std_array__regex: str = r".*"\n",
       "\n",
       "    # Signatures like\n",
       "    #       void foo_non_const(int output[2])\n",
       "    # may be transformed to:\n",
       "    #       void foo_non_const(BoxedInt & output_0, BoxedInt & output_1)         (c++ bound signature)\n",
       "    #       def foo_non_const(output_0: BoxedInt, output_0: BoxedInt) -> None    (python)\n",
       "    # fn_params_replace_c_array_modifiable_by_boxed__regex contains a list of regexes on functions names\n",
       "    # for which this transformation will be applied.\n",
       "    # Set it to r".*" to apply this to all functions, set it to "" to disable it\n",
       "    fn_params_replace_c_array_modifiable_by_boxed__regex: str = r".*"\n",
       "    # (c_array_modifiable_max_size is the maximum number of params that can be boxed like this)\n",
       "    fn_params_replace_modifiable_c_array__max_size = 10\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # C style string list functions and methods parameters\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Signatures like\n",
       "    #     void foo(const char * const items[], int items_count)\n",
       "    # may be transformed to:\n",
       "    #     void foo(const std::vector<std::string>& const items[])        (c++ bound signature)\n",
       "    #     def foo(items: List[str]) -> None                              (python)\n",
       "    # fn_params_replace_c_string_list_regexes contains a list of regexes on functions names\n",
       "    # for which this transformation will be applied.\n",
       "    # Set it to [r".*"] to apply this to all functions, set it to [] to disable it\n",
       "    fn_params_replace_c_string_list__regex: str = r".*"\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Make "immutable python types" modifiable, when passed by pointer or reference\n",
       "    # ------------------------------------------------------------------------------\n",
       "    #\n",
       "    # adapt functions params that use non const pointers or reference to a type that is immutable in python.\n",
       "\n",
       "    # Signatures like\n",
       "    #     int foo(int* value)\n",
       "    # May be transformed to:\n",
       "    #     def foo(BoxedInt value) -> int                                  (python)\n",
       "    # So that any modification done on the C++ side can be seen from python.\n",
       "    #\n",
       "    # fn_params_adapt_modifiable_immutable_regexes contains a list of regexes on functions names\n",
       "    # Set it to r".*" to apply this to all functions. Set it to "" to disable it\n",
       "    fn_params_replace_modifiable_immutable_by_boxed__regex: str = ""\n",
       "\n",
       "    # As an alternative, we can also add the modified value to the returned type\n",
       "    # of the function (which will now be a tuple)\n",
       "    #\n",
       "    # For example\n",
       "    #     int foo(int* value)\n",
       "    # May be transformed to:\n",
       "    #     def foo(int value) -> Tuple[int, bool]\n",
       "    # So that any modification done on the C++ side can be seen from python.\n",
       "    #\n",
       "    # fn_params_output_modifiable_immutable_to_return__regex contains a list of regexes on functions names\n",
       "    # Set it to r".*" to apply this to all functions. Set it to "" to disable it\n",
       "    fn_params_output_modifiable_immutable_to_return__regex: str = ""\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Custom adapters (advanced, very advanced and not documented here)\n",
       "    # fn_custom_adapters may contain callables of signature\n",
       "    #   f(adapted_function: AdaptedFunction) -> Optional[LambdaAdapter]\n",
       "    # ------------------------------------------------------------------------------\n",
       "    fn_custom_adapters: list[Any]\n",
       "\n",
       "    ################################################################################\n",
       "    #    <class, struct, and member adaptations>\n",
       "    ################################################################################\n",
       "\n",
       "    # Exclude certain classes and structs by a regex on their name\n",
       "    class_exclude_by_name__regex: str = ""\n",
       "    # Exclude certain members by a regex on their name\n",
       "    member_exclude_by_name__regex: str = ""\n",
       "    # Exclude members based on their type\n",
       "    member_exclude_by_type__regex: str = ""\n",
       "    # Make certain members read-only by a regex on their name\n",
       "    member_readonly_by_name__regex: str = ""\n",
       "    # Make certain members read-only based on their type\n",
       "    member_readonly_by_type__regex: str = ""\n",
       "\n",
       "    # class_create_default_named_ctor__regex / struct_create_default_named_ctor__regex:\n",
       "    # regex giving the list of class & struct names for which we want to generate a named\n",
       "    # constructor for Python, when no default constructor is provided by C++\n",
       "    # (by default, this is active for all structs and not for the classes,\n",
       "    #  in order for it to work, all struct members need to be default constructible if\n",
       "    #  they are not declared with a default value)\n",
       "    struct_create_default_named_ctor__regex: str = r".*"\n",
       "    class_create_default_named_ctor__regex: str = r""\n",
       "\n",
       "    # class_expose_protected_methods__regex:\n",
       "    # regex giving the list of class names for which we want to expose protected methods.\n",
       "    # (by default, only public methods are exposed)\n",
       "    # If active, this will use the technique described at\n",
       "    # https://pybind11.readthedocs.io/en/stable/advanced/classes.html#binding-protected-member-functions)\n",
       "    class_expose_protected_methods__regex: str = ""\n",
       "\n",
       "    # class_expose_protected_methods__regex:\n",
       "    # regex giving the list of class names for which we want to be able to override virtual methods\n",
       "    # from python.\n",
       "    # (by default, this is not possible)\n",
       "    # If active, this will use the technique described at\n",
       "    # https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python\n",
       "    #\n",
       "    # Note: if you want to override protected functions, also fill `class_expose_protected_methods__regex`\n",
       "    class_override_virtual_methods_in_python__regex: str = ""\n",
       "\n",
       "    # class_dynamic_attributes__regex\n",
       "    # By default, classes exported from C++ do not support dynamic attributes and the only writable attributes are\n",
       "    # the ones explicitly defined using class_::def_readwrite() or class_::def_property().\n",
       "    # If active, this will use the technique described at\n",
       "    # https://pybind11.readthedocs.io/en/stable/classes.html#dynamic-attributes\n",
       "    class_dynamic_attributes__regex: str = ""\n",
       "\n",
       "    # class_deep_copy__regex & class_copy__regex:\n",
       "    # By default, structs and classes exported from C++ do not support (deep)copy.\n",
       "    # However, if they do have a copy constructor (implicit or user defined),\n",
       "    # (deep)copy can be enabled by invoking this constructor.\n",
       "    # https://pybind11.readthedocs.io/en/stable/advanced/classes.html#deepcopy-support\n",
       "    class_deep_copy__regex: str = ""\n",
       "    class_copy__regex: str = ""\n",
       "    # If class_copy_add_info_in_stub=True, the existence of __copy__ and __deepcopy__\n",
       "    # will be mentioned in the stub file.\n",
       "    class_copy_add_info_in_stub: bool = False\n",
       "\n",
       "    # iterable classes: if some cpp classes expose begin()/end()/size(), they can be made iterable in python\n",
       "    # Make classes iterables by setting:\n",
       "    #     options.class_iterables_infos.add_iterable_class(python_class_name__regex, iterable_python_type_name)\n",
       "    class_iterables_infos: ClassIterablesInfos\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Templated class options\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Template class must be instantiated for the desired types, and a new name must be given for each instantiation\n",
       "    # See https://pybind11.readthedocs.io/en/stable/advanced/classes.html#binding-classes-with-template-parameters\n",
       "    #\n",
       "    # class_template_options enables to set this\n",
       "    #\n",
       "    # For example\n",
       "    # 1. this call would instantiate some classes for types "int" and "const char *", with a naming scheme:\n",
       "    #   MyClass<int> (cpp)  -> MyClassInt (python)\n",
       "    #   ------------------------------------------\n",
       "    #     options.class_template_options.add_specialization(\n",
       "    #         class_name_regex=r"^MyPrefix",                 # r"^MyPrefix" => select class names with this prefix\n",
       "    #         cpp_types_list=["int", "const char *"],        # instantiated types\n",
       "    #         naming_scheme=TemplateNamingScheme.camel_case_suffix\n",
       "    #     )\n",
       "    # 2. this call would ignore all template classes:\n",
       "    #        options.class_template_options.add_ignore(r".*")\n",
       "    #    would ignore all template functions (they will not be exported)\n",
       "    class_template_options: TemplateClassOptions\n",
       "    # if class_template_decorate_in_stub is True, then there will be some\n",
       "    # decorative comments in the stub file, in order to visually group\n",
       "    # the generated classes together\n",
       "    class_template_decorate_in_stub: bool = True\n",
       "\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # Adapt class members\n",
       "    # ------------------------------------------------------------------------------\n",
       "    # adapt class members which are a fixed size array of a numeric type:\n",
       "    #\n",
       "    # For example\n",
       "    #       struct Foo {  int values[10]; };\n",
       "    # May be transformed to:\n",
       "    #       class Foo:\n",
       "    #           values: numpy.ndarray\n",
       "    #\n",
       "    # i.e. the member will be transformed to a property that points to a numpy array\n",
       "    # which can be read/written from python (this requires numpy)\n",
       "    # This is active by default.\n",
       "    member_numeric_c_array_replace__regex: str = r".*"\n",
       "\n",
       "    # member_numeric_c_array_types: list of numeric types that can be stored in a numpy array\n",
       "    # for a class member which is a fixed size array of a numeric type\n",
       "    # - Synonyms (defined via. `typedef` or `using`) are allowed here\n",
       "    # - *don't* include char, *don't* include byte, those are not numeric!\n",
       "    #   See https://numpy.org/doc/stable/reference/generated/numpy.chararray.html\n",
       "    member_numeric_c_array_types: str = code_utils.join_string_by_pipe_char(\n",
       "        [\n",
       "            "int",\n",
       "            "unsigned int",\n",
       "            "long",\n",
       "            "unsigned long",\n",
       "            "long long",\n",
       "            "unsigned long long",\n",
       "            "float",\n",
       "            "double",\n",
       "            "long double",\n",
       "            "uint8_t",\n",
       "            "int8_t",\n",
       "            "uint16_t",\n",
       "            "int16_t",\n",
       "            "uint32_t",\n",
       "            "int32_t",\n",
       "            "uint64_t",\n",
       "            "int64_t",\n",
       "            "bool",\n",
       "        ]\n",
       "    )\n",
       "\n",
       "    ################################################################################\n",
       "    #    <namespace adaptations>\n",
       "    ################################################################################\n",
       "\n",
       "    # All C++ namespaces in this list will not be emitted as a submodule\n",
       "    # (i.e. their inner code will be placed in the root python module, or in the parent\n",
       "    # module)\n",
       "    namespaces_root: List[str]\n",
       "\n",
       "    # All C++ namespaces that match this regex will be excluded\n",
       "    # By default, any namespace whose name contains "internal" or "detail" will be excluded.\n",
       "    namespace_exclude__regex = r"[Ii]nternal|[Dd]etail"\n",
       "\n",
       "    ################################################################################\n",
       "    #    <enum adaptations>\n",
       "    ################################################################################\n",
       "    # Exclude certain enums by a regex on their name\n",
       "    enum_exclude_by_name__regex: str = ""\n",
       "    # Remove the typical "EnumName_" prefix from "C enum" values.\n",
       "    # For example, with the C enum:\n",
       "    #     enum MyEnum { MyEnum_A = 0, MyEnum_B };\n",
       "    # Values would be named "a" and "b" in python\n",
       "    enum_flag_remove_values_prefix: bool = True\n",
       "    # Skip count value from enums, for example like in:\n",
       "    #    enum MyEnum { MyEnum_A = 1, MyEnum_B = 1, MyEnum_COUNT };\n",
       "    enum_flag_skip_count: bool = True\n",
       "    # By default, all enums export rudimentary arithmetic and bit-level operations ( r".*" matches any enum name)\n",
       "    enum_make_arithmetic__regex: str = r".*"\n",
       "\n",
       "    ################################################################################\n",
       "    #    <define adaptations>\n",
       "    ################################################################################\n",
       "    # Simple preprocessor defines can be exported as global variables, e.g.:\n",
       "    #     #define MY_VALUE 1\n",
       "    #     #define MY_FLOAT 1.5\n",
       "    #     #define MY_STRING "abc"\n",
       "    #     #define MY_HEX_VALUE 0x00010009\n",
       "    # This is limited to *simple* defines (no param, string, int, float or hex only)\n",
       "    # By default nothing is exported\n",
       "    macro_define_include_by_name__regex: str = ""\n",
       "\n",
       "    ################################################################################\n",
       "    #    <post processing>\n",
       "    ################################################################################\n",
       "    # If you need to process the code after generation, fill these functions\n",
       "    postprocess_stub_function: Callable[[str], str] | None = None  # run at the very end\n",
       "    postprocess_pydef_function: Callable[[str], str] | None = None\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Sanity checks and utilities below>\n",
       "    ################################################################################\n",
       "    def check_options_consistency(self) -> None:\n",
       "        # the only authorized type are those for which the size is known with certainty\n",
       "        # * int and long are not acceptable candidates: use int8_t, uint_8t, int32_t, etc.\n",
       "        # * concerning float and doubles, there is no standard for fixed size floats, so we have to cope with\n",
       "        #   float, double and long double and their various platforms implementations...\n",
       "        authorized_types = [\n",
       "            "byte",\n",
       "            "uint8_t",\n",
       "            "int8_t",\n",
       "            "uint16_t",\n",
       "            "int16_t",\n",
       "            "uint32_t",\n",
       "            "int32_t",\n",
       "            "np_uint_l",  # Platform dependent: "uint64_t" on *nixes, "uint32_t" on windows\n",
       "            "np_int_l",  # Platform dependent: "int64_t" on *nixes, "int32_t" on windows\n",
       "            "float",\n",
       "            "double",\n",
       "            "long double",\n",
       "            "long long",\n",
       "        ]\n",
       "        for buffer_type in self._fn_params_buffer_types_list():\n",
       "            if buffer_type not in authorized_types:\n",
       "                raise ValueError(\n",
       "                    f"""\n",
       "                    options.build_types contains an unauthorized type: {buffer_type}\n",
       "                    Authorized types are: { ", ".join(authorized_types) }\n",
       "                    """\n",
       "                )\n",
       "\n",
       "    def _indent_cpp_spaces(self) -> str:\n",
       "        space = "\\t" if self.cpp_indent_with_tabs else " "\n",
       "        return space * self.cpp_indent_size\n",
       "\n",
       "    def _indent_python_spaces(self) -> str:\n",
       "        space = "\\t" if self.python_ident_with_tabs else " "\n",
       "        return space * self.python_indent_size\n",
       "\n",
       "    def _fn_params_buffer_types_list(self) -> list[str]:\n",
       "        return code_utils.split_string_by_pipe_char(self.fn_params_buffer_types)\n",
       "\n",
       "    def _fn_params_buffer_template_types_list(self) -> list[str]:\n",
       "        return code_utils.split_string_by_pipe_char(self.fn_params_buffer_template_types)\n",
       "\n",
       "    def _member_numeric_c_array_types_list(self) -> list[str]:\n",
       "        return code_utils.split_string_by_pipe_char(self.member_numeric_c_array_types)\n",
       "\n",
       "    def __init__(self) -> None:\n",
       "        # See doc for all the params at their declaration site (scroll up to the top of this file!)\n",
       "        from litgen.internal import cpp_to_python\n",
       "\n",
       "        self.srcmlcpp_options = SrcmlcppOptions()\n",
       "        self.srcmlcpp_options.header_filter_preprocessor_regions = True\n",
       "\n",
       "        self.type_replacements = cpp_to_python.standard_type_replacements()\n",
       "        self.value_replacements = cpp_to_python.standard_value_replacements()\n",
       "        self.comments_replacements = cpp_to_python.standard_comment_replacements()\n",
       "\n",
       "        self.function_names_replacements = RegexReplacementList()\n",
       "        self.var_names_replacements = RegexReplacementList()\n",
       "        self.macro_name_replacements = RegexReplacementList()\n",
       "        self.namespace_names_replacements = RegexReplacementList()\n",
       "\n",
       "        self.fn_template_options = TemplateFunctionsOptions()\n",
       "        self.class_template_options = TemplateClassOptions()\n",
       "\n",
       "        self.class_iterables_infos = ClassIterablesInfos()\n",
       "\n",
       "        self.fn_custom_adapters = []\n",
       "        self.namespaces_root = []\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from codemanip import code_utils\n", "from litgen.demo import litgen_demo\n", "\n", "litgen_options_code = code_utils.download_url_content(\n", " \"https://raw.githubusercontent.com/pthom/litgen/main/src/litgen/options.py\"\n", ")\n", "litgen_demo.show_python_code(litgen_options_code, title=\"litgen/options.py\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## srcmlcpp options\n", "\n", "litgen is based on srcmlcpp, which also provides some options, via `LitgenOptions.srcmlcpp_options`. They are available at [srcmlcpp/srcmlcpp_options.py](https://github.com/pthom/litgen/blob/main/src/srcmlcpp/srcmlcpp_options.py)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", " \n", " \n", "
\n", "
\n", " \n", "
\n", "
"""\n",
       "Options for srcmlcpp. Read the doc near all options elements.\n",
       """"\n",
       "from __future__ import annotations\n",
       "from typing import Callable, Optional\n",
       "\n",
       "from codemanip.code_utils import split_string_by_pipe_char\n",
       "from srcmlcpp.scrml_warning_settings import WarningType\n",
       "\n",
       "\n",
       "class SrcmlcppOptions:\n",
       "    ################################################################################\n",
       "    #    <API prefixes for functions / API comment suffixes for classes>\n",
       "    ################################################################################\n",
       "\n",
       "    # Prefixes that denote exported dll functions.\n",
       "    # For example, you could use "MY_API" which would be defined as `__declspec(dllexport|dllimport)` on windows\n",
       "    # You can have several prefixes: separate them with a "|", for example: "MY_API|OTHER_API"\n",
       "    #\n",
       "    # If you filled SrcmlcppOptions.functions_api_prefixes, then those prefixes will be mentioned\n",
       "    # as specifiers for the return type of the functions.\n",
       "    functions_api_prefixes: str = ""\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Numbers parsing: resolve macros values>\n",
       "    ################################################################################\n",
       "\n",
       "    # List of named possible numbers or sizes (fill it if some number/sizes are defined by macros or constexpr values)\n",
       "    # For example it could store `{ "SPACE_DIMENSIONS" : 3 }` if the C++ code uses a macro `SPACE_DIMENSIONS`\n",
       "    named_number_macros: dict[str, int]\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Exclude certain regions based on preprocessor macros>\n",
       "    ################################################################################\n",
       "\n",
       "    # Set header_filter_preprocessor_regions to True if the header has regions\n",
       "    # that you want to exclude from the parsing, like this:\n",
       "    #       #ifdef SOME_RARE_OPTION\n",
       "    #           // code we want to exclude\n",
       "    #       #endif\n",
       "    #\n",
       "    # See srcmlcpp/filter_preprocessor_regions.py for more complete examples\n",
       "    header_filter_preprocessor_regions: bool = False\n",
       "    # If header_filter_preprocessor_regions is True,\n",
       "    # you need to also fill header_filter_acceptable__regex in order to accept code contained\n",
       "    # inside header_guards (and other acceptable preprocessor defines you may set via this regex)\n",
       "    # Your regex can have several options: separate them with a "|".\n",
       "    # By default, all macros names ending with "_H", "HPP", "HXX" are considered as acceptable.\n",
       "    header_filter_acceptable__regex: str = "__cplusplus|_h_$|_h$|_H$|_H_$|hpp$|HPP$|hxx$|HXX$"\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Custom preprocess of the code>\n",
       "    ################################################################################\n",
       "\n",
       "    #\n",
       "    # If you need to preprocess the code before parsing, fill this function\n",
       "    #\n",
       "    code_preprocess_function: Optional[Callable[[str], str]] = None\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Misc options>\n",
       "    ################################################################################\n",
       "\n",
       "    # Encoding of python and C++ files\n",
       "    encoding: str = "utf-8"\n",
       "\n",
       "    # Preserve empty lines, i.e. any empty line in the C++ code will be mentioned as a CppEmptyLine element\n",
       "    # this is done by adding a dummy comment on the line.\n",
       "    preserve_empty_lines: bool = True\n",
       "\n",
       "    # flag_srcml_dump_positions: if True, code positions will be outputted in the xml tree (recommended)\n",
       "    flag_srcml_dump_positions: bool = True\n",
       "\n",
       "    # indentation used by CppElements str_code() methods (4 spaces by default)\n",
       "    indent_cpp_str: str = "    "\n",
       "\n",
       "    ################################################################################\n",
       "    #    <Verbose / Quiet mode>\n",
       "    ################################################################################\n",
       "\n",
       "    # if quiet, all warning messages are discarded (warning messages go to stderr)\n",
       "    flag_quiet: bool = False\n",
       "\n",
       "    # List of ignored warnings\n",
       "    ignored_warnings: list[WarningType]\n",
       "    # List of ignored warnings, identified by a part of the warning message\n",
       "    ignored_warning_parts: list[str]\n",
       "\n",
       "    # Show python callstack when warnings are raised\n",
       "    flag_show_python_callstack: bool = False\n",
       "\n",
       "    # if true, display parsing progress during execution (on stdout)\n",
       "    flag_show_progress: bool = False\n",
       "\n",
       "    ################################################################################\n",
       "    # Workaround for https://github.com/srcML/srcML/issues/1833\n",
       "    ################################################################################\n",
       "    fix_brace_init_default_value = True\n",
       "\n",
       "    ################################################################################\n",
       "    #    <End>\n",
       "    ################################################################################\n",
       "\n",
       "    def __init__(self) -> None:\n",
       "        # See doc for all the params at their declaration site (scroll up!)\n",
       "        self.named_number_macros = {}\n",
       "        self.ignored_warnings = []\n",
       "        self.ignored_warning_parts = []\n",
       "\n",
       "    def functions_api_prefixes_list(self) -> list[str]:\n",
       "        assert isinstance(self.functions_api_prefixes, str)\n",
       "        return split_string_by_pipe_char(self.functions_api_prefixes)\n",
       "\n",
       "\n",
       "def _int_from_str_or_named_number_macros(options: SrcmlcppOptions, int_str: Optional[str]) -> Optional[int]:\n",
       "    if int_str is None:\n",
       "        return None\n",
       "\n",
       "    try:\n",
       "        v = int(int_str)\n",
       "        return v\n",
       "    except ValueError:\n",
       "        if int_str in options.named_number_macros:\n",
       "            return options.named_number_macros[int_str]\n",
       "        else:\n",
       "            return None\n",
       "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "litgen_options_code = code_utils.download_url_content(\n", " \"https://raw.githubusercontent.com/pthom/litgen/main/src/srcmlcpp/srcmlcpp_options.py\"\n", ")\n", "litgen_demo.show_python_code(litgen_options_code, title=\"srcmlcpp/srcmlcpp_options.py\")" ] } ], "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 }