Export Functions

Guide to export functions from your python plugin to be used by other language modules within Plugify.

In the Plugify ecosystem, Python plugins can export functions to make them accessible to other plugins. This guide explains how to define and export functions in Python and provides examples to help you integrate your plugins seamlessly.

Basic Type Mapping

The following table lists how types are exposed to the Python API:

C++ TypePython TypePlugify AliasRef Support ?
voidNonevoid❌
boolboolbool✅
charstrchar8✅
char16_tstrchar16✅
int8_tintint8✅
int16_tintint16✅
int32_tintint32✅
int64_tintint64✅
uint8_tintuint8✅
uint16_tintuint16✅
uint32_tintuint32✅
uint64_tintuint64✅
uintptr_tintptr64✅
uintptr_tintptr32✅
floatfloatfloat✅
doublefloatdouble✅
void*Callablefunction❌
plg::stringstrstring✅
plg::anyAnyany✅
plg::vector<bool>list[bool]bool✅
plg::vector<char>list[str]char8✅
plg::vector<char16_t>list[str]char16✅
plg::vector<int8_t>list[int]int8✅
plg::vector<int16_t>list[int]int16✅
plg::vector<int32_t>list[int]int32✅
plg::vector<int64_t>list[int]int64✅
plg::vector<uint8_t>list[int]uint8✅
plg::vector<uint16_t>list[int]uint16✅
plg::vector<uint32_t>list[int]uint32✅
plg::vector<uint64_t>list[int]uint64✅
plg::vector<uintptr_t>list[int]ptr64✅
plg::vector<uintptr_t>list[int]ptr32✅
plg::vector<float>list[float]float✅
plg::vector<double>list[float]double✅
plg::vector<plg::string>list[str]string✅
plg::vector<plg::any>list[Any]any✅
plg::vector<plg::vec2>list[Vector2]vec2✅
plg::vector<plg::vec3>list[Vector3]vec3✅
plg::vector<plg::vec4>list[Vectpr4]vec4✅
plg::vector<plg::mat4x4>list[Matrix4x4]mat4x4✅
plg::vec2Vector2vec2✅
plg::vec3Vector3vec3✅
plg::vec4Vector4vec4✅
plg::mat4x4Matrix4x4mat4x4✅

Exporting Functions in Python

Exporting functions in Python is simpler than in C++ because Python is a dynamically-typed language. You only need to define the function and specify it in the plugin manifest. Plugify's Python Language Module handles the rest.

Basic Example

Here’s a simple example of exporting a function in a Python plugin:

Function Definition

plugin.py
def add_numbers_exported(a: int, b: int) -> int:
    """
    Adds two integers.

    :param a: First integer.
    :param b: Second integer.
    :return: Sum of a and b.
    """
    return a + b

Plugin Manifest

To export the function, describe it in the plugin manifest under the methods section:

plugin_name.pplugin
{
  "name": "ExamplePythonPlugin",
  "version": "1.0.0",
  "methods": [
    {
      "name": "add_numbers",
      "funcName": "add_numbers_exported",
      "paramTypes": [
        {
          "type": "int32",
          "name": "a"
        },
        {
          "type": "int32",
          "name": "b"
        }
      ],
      "retType": {
        "type": "int32"
      }
    }
  ]
}

Advanced Example: Exporting Complex Functions

Here’s an example of exporting a function with complex parameter and return types:

Function Definition

plugin.py
def process_data_exported(data: list[float], prefix: str) -> list[str]:
    """
    Processes a list of floats and returns a list of strings.

    :param data: List of float values.
    :param prefix: Prefix to add to each value.
    :return: List of formatted strings.
    """
    return [f"{prefix}{value}" for value in data]

Plugin Manifest

plugin_name.pplugin
{
  "name": "ExamplePythonPlugin",
  "version": "1.0.0",
  "methods": [
    {
      "name": "process_data",
      "funcName": "process_data_exported",
      "paramTypes": [
        {
          "type": "float[]",
          "name": "data"
        },
        {
          "type": "string",
          "name": "prefix"
        }
      ],
      "retType": {
        "type": "string[]"
      }
    }
  ]
}

Exporting Functions with References

Plugify supports reference parameters in dynamically-typed languages like Python, but they work differently than in statically-typed languages. In Python, you cannot directly modify parameters passed by reference. Instead, you must return a tuple where:

  1. First element: The function's return value (use None if the function returns void)
  2. Remaining elements: Modified values for all reference parameters, in order

Function Definition with Reference Parameters

plugin.py
def increment_value_exported(value: int) -> tuple[None, int]:
    """
    Increments an integer value by reference.

    :param value: The value to increment.
    :return: Tuple of (None, modified_value).
    """
    return None, value + 1

def calculate_exported(a: int, b: int, sum: int, product: int) -> tuple[None, int, int]:
    """
    Calculates sum and product of two numbers, returning both via reference.

    :param a: First number.
    :param b: Second number.
    :param sum: Output parameter for sum (passed by reference).
    :param product: Output parameter for product (passed by reference).
    :return: Tuple of (None, sum, product).
    """
    calculated_sum = a + b
    calculated_product = a * b
    return None, calculated_sum, calculated_product

def process_and_count_exported(data: list[float], prefix: str, count: int) -> tuple[list[str], int]:
    """
    Processes data and returns both result and count.

    :param data: List of float values.
    :param prefix: Prefix to add to each value.
    :param count: Output parameter for count (passed by reference).
    :return: Tuple of (result, count).
    """
    result = [f"{prefix}{value}" for value in data]
    return result, len(data)

Plugin Manifest with Reference Parameters

In the manifest, mark parameters that should be treated as references using "ref": true:

plugin_name.pplugin
{
  "name": "ExamplePythonPlugin",
  "version": "1.0.0",
  "methods": [
    {
      "name": "increment_value",
      "funcName": "increment_value_exported",
      "paramTypes": [
        {
          "type": "int32",
          "name": "value",
          "ref": true
        }
      ],
      "retType": {
        "type": "void"
      }
    },
    {
      "name": "calculate",
      "funcName": "calculate_exported",
      "paramTypes": [
        {
          "type": "int32",
          "name": "a"
        },
        {
          "type": "int32",
          "name": "b"
        },
        {
          "type": "int32",
          "name": "sum",
          "ref": true
        },
        {
          "type": "int32",
          "name": "product",
          "ref": true
        }
      ],
      "retType": {
        "type": "void"
      }
    },
    {
      "name": "process_and_count",
      "funcName": "process_and_count_exported",
      "paramTypes": [
        {
          "type": "float[]",
          "name": "data"
        },
        {
          "type": "string",
          "name": "prefix"
        },
        {
          "type": "int32",
          "name": "count",
          "ref": true
        }
      ],
      "retType": {
        "type": "string[]"
      }
    }
  ]
}

How It Works

  1. Return Order: The first return value is the function's actual return value. Subsequent values correspond to reference parameters in order.
  2. Void Functions: If the function returns void, the first element of the tuple must be None.
  3. Mixed Returns: If a function has both a return value and reference parameters, the return value comes first, followed by all reference parameters.
  4. Type Hints: Use tuple[ReturnType, RefType1, RefType2, ...] for proper type annotations.

Reference Parameter Support

Reference parameters work with most Plugify types as shown in the "Ref Support" column of the type mapping table. The following types do not support references:

  • void/None (cannot be passed by reference)
  • function (callback types)

All other types including primitives, strings, and lists support reference parameters via the tuple return pattern.

Handling Callbacks

Plugify allows you to export functions that accept callbacks as parameters. Here’s an example:

Function Definition

plugin.py
def execute_with_callback_exported(value: int, input_str: str, callback: callable) -> None:
    """
    Executes a callback function with the provided parameters.

    :param value: Integer value.
    :param input_str: Input string.
    :param callback: Callback function to execute.
    """
    result = callback(value, input_str)
    print(f"Callback result: {result}")

Plugin Manifest

plugin_name.pplugin
{
  "name": "ExamplePythonPlugin",
  "version": "1.0.0",
  "methods": [
    {
      "name": "execute_with_callback",
      "funcName": "execute_with_callback_exported",
      "paramTypes": [
        {
          "type": "int32",
          "name": "value"
        },
        {
          "type": "string",
          "name": "input_str"
        },
        {
          "type": "function",
          "name": "callback",
          "prototype": {
            "name": "example_callback",
            "funcName": "example_callback_exported",
            "paramTypes": [
              {
                "type": "int32",
                "name": "value"
              },
              {
                "type": "string",
                "name": "input_str"
              }
            ],
            "retType": {
              "type": "string"
            }
          }
        }
      ],
      "retType": {
        "type": "void"
      }
    }
  ]
}

Best Practices

  1. Define Functions Clearly: Ensure your functions are well-documented and easy to understand.
  2. Follow Type Conventions: Adhere to Plugify's type conventions for parameters and return values.
  3. Test Thoroughly: Test your exported functions to ensure they work as expected when called by other plugins.
  4. Update the Manifest: Always describe exported functions in the plugin manifest under the methods section.

Conclusion

Exporting functions in Python plugins is simple and straightforward. By defining your functions and describing them in the plugin manifest, you can create robust and interoperable plugins. For more advanced use cases, such as handling callbacks, use the techniques outlined in this guide.