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