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 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 Adding a custom function 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 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

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

Name

Type

Explanation

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).

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.

ignored_classes

List of strings

List of C++ class names (without any template argument). These classes will be ignored (but still parsed, unlike with ignored_headers) and no binding code generated.

user_defined_headers

List of strings

Paths to user-defined bindings that will be called when generating the overall bindings (see class options and Adding a custom function 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.

enums

Dictionary

Mapping from C++ enum name to an enum configuration.

classes

Dictionary

Mapping from C++ class name (untemplated) to a class configuration.

functions

List of dictionaries

List of function configuration. These are for free functions, not class methods.

Warning

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

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

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: "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 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 arithmetic flag to the configuration options to handle this.

Class-level options

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

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

Name

Type

Explanation

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.

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 user_defined_headers. See Adding a custom function binding for more info.

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 for more info.

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.

ignore_repr

Boolean

In python the __repr__ method is equivalent to the 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

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.

methods

List of dictionaries

List of function configuration.

Function-level options

{
  "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"
}
Parameters

Name

Type

Explanation

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 ;

static

Boolean

Whether this function is static. In the case of free functions (not related to a class), it should be false.

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

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.

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.

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.

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 documentation

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 documentation

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 keep_alive and return_policy are correctly set if you get a warning in the log, then set this to true to ignore the warning.

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.

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.