A library for providing inter-language foreign function interface calls
Project description
A library for providing inter-language foreign function interface calls
Abstract
METACALL Python Port is the port of METACALL to Python Programming Language. With METACALL Python Port you can transparently execute code from Python to any programming language, for example, calling JavaScript, NodeJS, Ruby or C# code from Python.
Install
Install MetaCall binaries first:
curl -sL https://raw.githubusercontent.com/metacall/install/master/install.sh | bash
Then install MetaCall Python package through MetaCall:
pip3 install metacall
Example
Calling Ruby from Python
multiply.rb
def multiply(left, right)
return left * right
end
main.py
from metacall import metacall_load_from_file, metacall
metacall_load_from_file('rb', [ 'multiply.rb' ])
metacall('multiply', 3, 4); # 12
Calling NodeJS from Python (MonkeyPatch API)
sum.js
module.exports = {
sum: (x, y) => x + y,
};
main.py
import metacall
from sum.js import sum
sum(3, 4); # 7
Running the example:
python3 main.py
Using pointers (calling to a C library)
For a simple case, let’s imagine that we have a simple C function that has an ‘in’ parameter and we want to pass a pointer to a long, from Python side, and then store some value there for reading it later on. Let’s assume we have a loadtest.h and libloadtest.so and a C function from this library could be this one:
void modify_int_ptr(long *l)
{
*l = 111;
}
Now if we want to call it from Python side, we should do the following:
from metacall import metacall_load_from_package, metacall, metacall_value_reference, metacall_value_dereference
# Load the library (we can configure the search paths for the .so and .lib with metacall_execution_path)
# metacall_execution_path('c', '/usr/local/include')
# metacall_execution_path('c', '/usr/local/lib')
metacall_load_from_package('c', 'loadtest')
# Create value pointer (int *)
int_val = 324444
int_val_ref = metacall_value_reference(int_val)
# Pass the pointer to the function
metacall('modify_int_ptr', int_val_ref)
# Get the value from pointer
int_val_deref = metacall_value_dereference(int_val_ref)
print(int_val_deref, '==', 111)
For a more complex case, where we have an in/out parameter, for example an opaque struct that we want to alloc from C side. First of all, with the following header loadtest.h:
#ifndef LIB_LOAD_TEST_H
#define LIB_LOAD_TEST_H 1
#if defined(WIN32) || defined(_WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <cstdint>
typedef struct
{
uint32_t i;
double d;
} pair;
typedef struct
{
uint32_t size;
pair *pairs;
} pair_list;
EXPORT int pair_list_init(pair_list **t);
EXPORT double pair_list_value(pair_list *t, uint32_t id);
EXPORT void pair_list_destroy(pair_list *t);
#ifdef __cplusplus
}
#endif
#endif /* LIB_LOAD_TEST_H */
With the following implementation loadtest.cpp:
#include "loadtest.h"
int pair_list_init(pair_list **t)
{
static const uint32_t size = 3;
*t = new pair_list();
(*t)->size = size;
(*t)->pairs = new pair[(*t)->size];
for (uint32_t i = 0; i < size; ++i)
{
(*t)->pairs[i].i = i;
(*t)->pairs[i].d = (double)(((double)i) * 1.0);
}
return 0;
}
double pair_list_value(pair_list *t, uint32_t id)
{
return t->pairs[id].d;
}
void pair_list_destroy(pair_list *t)
{
delete[] t->pairs;
delete t;
}
In this case the structs are not opaque, but they can be opaque and it will work in the same way. Now, we can call those functions in the following manner:
from metacall import metacall_load_from_package, metacall, metacall_value_create_ptr, metacall_value_reference, metacall_value_dereference
metacall_load_from_package('c', 'loadtest')
# Create a pointer to void* set to NULL
list_pair = metacall_value_create_ptr(None)
# Create a reference to it (void**)
list_pair_ref = metacall_value_reference(list_pair)
# Call the function
result = metacall('pair_list_init', list_pair_ref)
# Get the result updated (struct allocated)
list_pair = metacall_value_dereference(list_pair_ref)
# Pass it to a function
result = metacall('pair_list_value', list_pair, 2)
# Destroy it
metacall('pair_list_destroy', list_pair)
# Here result will be 2.0 because is the third element in the array of pairs inside the struct
print(result, '==', 2.0)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file metacall-0.5.3.tar.gz
.
File metadata
- Download URL: metacall-0.5.3.tar.gz
- Upload date:
- Size: 10.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 |
f3b99d643f9b464ef61781f548a92909b720402cd9cf81fe50e30837f6213a78
|
|
MD5 |
ee7116c714a3867ab9b8c61c72073c71
|
|
BLAKE2b-256 |
1a0951182df17ea85d5ba257913aa9e675b6087c6d942a62f91b5697e1ab5fb1
|
File details
Details for the file metacall-0.5.3-py3-none-any.whl
.
File metadata
- Download URL: metacall-0.5.3-py3-none-any.whl
- Upload date:
- Size: 7.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 |
2d44abbdaa76f30f9e9c801ce20b60d6efbfe83261f70f655a2c06986c7ba840
|
|
MD5 |
f6fe1d04716727931033a74f78f5a86a
|
|
BLAKE2b-256 |
ea0af1c71ba2ac476358a71b52772227735c3d619c503441c93d708d72b6987d
|