Modifying the bindings through JSON configuration files
========================================================

The bindings and the generated code can be customized through JSON configuration files.
These files will be read and interpreted by the generator code.

They are located in the :code:`modules/python/config` folder of the ViSP source code.
After modifying them, you should retrigger the build of the python bindings.

When something cannot be resolved through configuration files, you should revert to using a :ref:`Custom binding`.


Root configuration file
---------------------------------------

The general configuration file is generated by the build system (CMake), it contains the arguments to the generator script.

It contains:

* The list of include directories used when compiling ViSP C++. They are used to resolve include of 3rd parties and find the **vpConfig.h** file

* A set of preprocessor macros that will be used when parsing C++ files with the generator. These are system and compiler dependent.

* For each module (core, imgproc, etc.), the list of header files that should be parsed.


A module can be ignored through the **CMakeLists.txt** configuration of the python module.

Each module has a dedicated JSON configuration file, located in the :code:`modules/python/config` folder.


Module configuration
--------------------------------------------

Configuration files have a top-down structure: First come the general module options,
then class/enum options, and for each of those, method/value configurations.

Module-level options
^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: json

  {
    "required_headers": ["visp3/core/vpPoint.h"],
    "ignored_headers": ["vpGEMM.h", "vpDebug.h"],
    "ignored_classes": ["vpException", "vpImageException"],
    "user_defined_headers": ["core.hpp"],
    "header_additional_dependencies": {
      "vpUKSigmaDrawerMerwe.h": ["vpUnscentedKalman.h"]
    },
    "enums": {},
    "classes": {},
    "functions": {}
  }


.. list-table:: Parameters
   :header-rows: 1

   * - Name
     - Type
     - Explanation
   * - :code:`required_headers`
     - List of strings
     - List of full header paths. These headers are forcefully included. Should be used if for some reason, the already included ViSP headers are not sufficient.
       By default, each parsed header is added to the includes of this module's binding source (.cpp file compiled with PyBind).
   * - :code:`ignored_headers`
     - List of strings
     - List of header file names, not including the module path. Each of these headers will be **completely** skipped.
       No preprocessing, no parsing, no binding generation. Useful if a header generates errors on parsing.
   * - :code:`ignored_classes`
     - List of strings
     - List of C++ class names (without any template argument).
       These classes will be ignored (but still parsed, unlike with :code:`ignored_headers`) and no binding code generated.
   * - :code:`user_defined_headers`
     - List of strings
     - Paths to user-defined bindings that will be called when generating the overall bindings
       (see class options and :ref:`Custom binding`). These paths are relative to the **modules/python/bindings/include** folder.
       If a file does not exist, an error will be raised at compile time.
   * - :code:`header_additional_dependencies`
     - Dictionary of header name to list of header names
     - Forcefully specify that a header (defined as a key of the dictionary) depends on all the headers listed as the values.
       This is helpful if your header depends on typedefs defined in other non-related (i.e., not linked by inheritance) files.
       In the example above, vpUKSigmaDrawerMerwe uses a typedef from vpUnscentedKalman, but the link is not seen by the generator.
   * - :code:`enums`
     - Dictionary
     - Mapping from C++ enum name to an :ref:`enum configuration <Enum options>`.
   * - :code:`classes`
     - Dictionary
     - Mapping from C++ class name (untemplated) to a :ref:`class configuration <Class options>`.
   * - :code:`functions`
     - List of dictionaries
     - List of :ref:`function configuration <Function options>`. These are for free functions, not class methods.


.. warning::

  Exceptions are not handled: they should always be placed in :code:`ignored_classes`.

  When a ViSP exception is thrown to the Python interpreter, it is converted to a RuntimeError


.. _Enum options:

Enum-level options
^^^^^^^^^^^^^^^^^^^

If an enum does not appear in the configuration dictionary, it takes on the default values of each option.

For enums there is only a single option: :code:`"ignore"`, which is a boolean.
If this flag is true, no binding is generated for this enum. The default value is **false**.


.. note::

  By design, all exported ViSP enumerations are of the arithmetic kind.
  It is thus possible to do :python:`Enum.value1 | Enum.value2`.
  Not all enumerations should actually behave like this,
  but it is not trivial to automatically determine which require arithmetic capabalities.

  A possible improvement would be to add an :code:`arithmetic` flag to the configuration options to handle this.

.. _Class options:

Class-level options
^^^^^^^^^^^^^^^^^^^

If a class does not appear in the configuration dictionary, it takes on the default value of each option.


.. code-block:: json

  "ignored_attributes": ["myAttribute"]
  "additional_bindings": "bindings_vpArray2D",
  "use_buffer_protocol": true,
  "specializations": [
    {
      "python_name": "ArrayDouble2D",
      "arguments": ["double"]
    }
  ]
  "ignore_repr": true,
  "is_virtual": true,
  "methods": {}


.. list-table:: Parameters
   :header-rows: 1

   * - Name
     - Type
     - Explanation
   * - :code:`ignored_attributes`
     - List of strings
     - List of attribute names. Each of the corresponding attributes will be ignored when generating binding code.
       By default, binding code is generated only for public fields that are not pointers or other hard to translate types.
   * - :code:`additional_bindings`
     - String
     - Name of a C++ function, defined in **User-defined binding code**.
       Should be visible from the module's .cpp file and have to correct signature.
       This means that the header file in which it is defined should be included in :code:`user_defined_headers`.
       See :ref:`Custom binding` for more info.
   * - :code:`use_buffer_protocol`
     - Boolean
     - Whether to add the buffer protocol to this object. This is a PyBind specific thing,
       and is helpful to automatically interpret an object of this class as an iterable/array (e.g., list) on the python side.
       This should be defined by hand in user-defined bindings. See the
       `Pybind documentation <https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html#buffer-protocol>`_
       for more info.

   * - :code:`specializations`
     - List of dictionaries
     - Only required for templated classes. Templating does not exist in Python, and Pybind can only generate bindings for
       classes that are fully specialized. Thus, it is required to declare the specializations.
       A specialization contains: the Python name of the class as well as the C++ types that will replace the generic template typenames.
       The C++ types should be in the same order as the template parameters.
   * - :code:`ignore_repr`
     - Boolean
     - In python the :python:`__repr__` method is equivalent to the :code:`operator<<(std::ostream&, Cls& self)` function
       allowing to print an object in the terminal. By default, the generator tries to find the C++ defined operator to generate a Python representation.
       If this is not desired, set this flag to true. You can define a custom representation through custom bindings.

       .. warning::
          Long to string representations (matrices, images) can flood the terminal.
          This is problematic if this happens when Pybind throws an error for an incorrect method call
   * - :code:`is_virtual`
     - Boolean
     - Whether to force this class to be considered as purely virtual (cannot be instanciated in Python)

       .. note::
          While most purely virtual classes are correctly detected, classes that inherit from an abstract one
          but do not implement its methods are not correctly detected, which will raise an error at compile time.
          It is for these cases that this flag is required.
   * - :code:`methods`
     - List of dictionaries
     - List of :ref:`function configuration <Function options>`.


.. _Function options:

Function-level options
^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: json

  {
    "signature": "vpImage<Type>& fn(vpImage<vpRGBa>&, Type, double&)",
    "static": false,
    "ignore": false,
    "use_default_param_policy": false,
    "param_is_input": [true, true, false],
    "param_is_output": [false, true, true],
    "return_policy": "reference",
    "keep_alive": [1, 0],
    "returns_ref_ok": true,
    "specializations":
    [
      ["unsigned char"],
      ["vpRGBa"]
    ],
    "custom_name": "function_name"
  }

.. list-table:: Parameters
   :header-rows: 1

   * - Name
     - Type
     - Explanation
   * - :code:`signature`
     - String
     - Signature of the function for which the functions apply.

       * Signature does not include the name of the parameters
       * The templated types should not be replaced with specializations.
       * Spaces are stripped when matching with parsed signatures
       * Signature does not include the *;*

   * - :code:`static`
     - Boolean
     - Whether this function is static. In the case of free functions (not related to a class), it should be false.
   * - :code:`ignore`
     - Boolean
     - Whether the binding for this method should be skipped. Defaults to false.

       .. note::

          If you provide an alternative to this function through custom bindings,
          you should set this to true so that the default is ignored or no warning is emitted

   * - :code:`use_default_param_policy`
     - Boolean
     - Whether to use the default parameter policy. With this policy,
       non-const references (**&**) to types that are immutable in Python (including STL containers)
       are considered as both inputs and outputs. Defaults to false.
       If true, no warning is emitted in the logs about parameter policy

       .. note::

          This is required since we do not know whether
          the references are used as inputs or outputs (or both) of the function.

       When a parameter is an output, it is either returned (it is the only output) or it is aggregated to a result tuple.


   * - :code:`param_is_input`
     - List of booleans
     - For a function with n arguments, a list of n booleans. at index i, describes whether the i-eth parameter is an input.
       If false, a default value is created.
       Requires that the type is default constructible.

       .. warning::

          The basic types (int, double, etc.) are left uninitialized.

   * - :code:`param_is_output`
     - List of booleans
     - For a function with n arguments, a list of n booleans. at index i, describes whether the i-eth parameter is an output.
       if true it is added to the return tuple.
   * - :code:`return_policy`
     - String
     - How C++ returns the type to Python. If there are issues about unwanted copies or memory freeing, configure this.
       See `The Pybind return value policies documentation <https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies>`_
   * - :code:`keep_alive`
     - 2-tuple of ints or List of 2-tuples
     - Dictates the lifetime of arguments and return types.
       Each tuple indicates that the second argument should be kept alive until the first argument is deleted.
       0 indicates the return value, 1 indicates self.
       See `The pybind keep alive documentation <https://pybind11.readthedocs.io/en/stable/advanced/functions.html#keep-alive>`_
   * - :code:`returns_ref_ok`
     - Boolean
     - If this function returns a ref, mark it as ok or not. Returning a ref may lead to double frees or copy depending on return policy.
       Make sure that :code:`keep_alive` and :code:`return_policy` are correctly set if you get a warning in the log, then set this to true to ignore the warning.
   * - :code:`specializations`
     - List of list of strings
     - Each list of string denotes a specialization, for a templated function. For each specialization,
       each string is a typename that is used to instanciate the template.
       The typenames should be in the same order ar the template specification of the function.
       If there are multiple specializations, the function will be overloaded.
   * - :code:`custom_name`
     - String
     - Rename this function to another name. Especially useful in the case of both static and member functions having the same name, which is forbidden by Pybind11.
