Quick Start

As previously mentioned, HookMan is a python application that uses plugins written in C/C++.

In order to integrate this project in your application, it’s necessary to create a configuration object named HookSpecs. This object provides pieces of information related to which hooks are available and which arguments are expected to be sent or received.

The block code below exemplifies a valid HookSpecs configuration:

from hookman.hooks import HookSpecs

def env_temperature(arg1: 'double', arg2: 'double') -> 'double':
    """
    Docs for Environment Temperature
    """

def friction_factor(arg1: 'int', arg2: 'double') -> 'double':
    """
    Docs for Friction Factor
    """

specs = HookSpecs(
    project_name='Acme',
    version='1',
    pyd_name='_alfasim_hooks',
    hooks=[
        env_temperature,
        friction_factor,
    ]
)

With the HookSpecs defined, it’s possible to generate the necessary files to interact between the application and the plugins implementation.

$ python -m hookman generate-project-files hook_specs.py --dst-path <DEST_DIR>

The output from the command above will be the following files:

  • HookCaller.hpp

  • HookCallerPython.cpp

  • CMakeLists.txt

These files contain all code necessary to make the project pybind11_ integrates with your application, and the CMakeLists file contains a boilerplate to compile and generate the binary extensions (.pyd file)

Important

Noticed that the macro PYBIND11_MODULE (on HookCallerPython.cpp) defines the module name that should be used to import these bindings, and this name is used on the HookSpecs object with the field “pyd_name”.

With the files generated, and compiled., it’s possible now to get an instance of the HookCaller object that holds all information related with the hooks implementation.

from acme_project import specs

# Initializing a class
hook_manager = HookMan(specs=specs, plugin_dirs=['path1', 'path2'])

hook_caller = hook_manager.get_hook_caller()

# Getting access to the hook implementation
friction_factor = hook_caller.friction_factor()
env_temperature = hook_caller.env_temperature()

# Checking if the hook was implemented
assert friction_factor is not None
assert env_temperature is None

The object hook_caller contains all references for the functions implemented in the plugins, you can access these methods directly or pass this reference to another module or a C++ function.

Executing in python

The example below shows how to execute the method in a python module.

from acme_project import specs

# Initializing a class
hook_manager = HookMan(specs=specs, plugin_dirs=['path1', 'path2'])
hook_caller = hook_manager.get_hook_caller()

# Getting access to the hook implementation
friction_factor_function = hook_caller.friction_factor()

#Executing the method implemented in one of the plugins.
ff_result = friction_factor_function(1, 2.5).

print(f"Result from friction_factor hook: {ff_result}")

Executing in C++

As mentioned on the pybind11 functional documentation, the C++11 standard brought the generic polymorphic function wrapper std::function<> , which enable powerful new ways of working with functions.

Example of a C++ function that takes an arbitrary function and execute it.
 int friction_factor(const std::function<double(int, double)> &f) {
     return f(10, 2.5);
 }

With the binding code for this function in place, it’s possible to pass a function implemented on one of the plugins directly to C++.

binding_code.cpp
#include <pybind11/functional.h>

 PYBIND11_MODULE(my_cpp_binding_module, m) {
     m.def("func_friction_factor", &friction_factor);

 }

The example below shows how to create an object hook_caller, and pass a function implemented on one of the plugins directly to C++ a function.

from acme_project import specs

# Initializing a class
hook_manager = HookMan(specs=specs, plugin_dirs=['path1', 'path2'])
hook_caller = hook_manager.get_hook_caller()

# Getting access to the hook implementation
friction_factor_function = hook_caller.friction_factor()

# Importing the binding with the cpp code
import my_cpp_binding_module

# Passing the Friction Factor function to C++
my_cpp_binding_module.func_friction_factor(friction_factor_function)