Skip to main content
Version: 0.8

Introduction

KCL provides plugin support through a plugin agent and auxiliary command line tools, and the KCL plugin framework supports different general-purpose languages to develop plugins. The KCL plugin framework currently supports the development of plugins in Python and Go languages.

KCL plugin Git repository: https://github.com/kcl-lang/kcl-plugin

Use Go to Write Plugins

0. Prerequisites

Using the KCL Go plugin requires the presence of Go 1.21+ in your PATH and add the dependency of KCL Go SDK

1. Hello Plugin

Write the following Go code and add the dependency of the hello plugin

package main

import (
"fmt"

"kcl-lang.io/kcl-go/pkg/kcl"
"kcl-lang.io/kcl-go/pkg/native" // Import the native API
_ "kcl-lang.io/kcl-go/pkg/plugin/hello_plugin" // Import the hello plugin
)

func main() {
// Note we use `native.MustRun` here instead of `kcl.MustRun`, because it needs the cgo feature.
yaml := native.MustRun("main.k", kcl.WithCode(code)).GetRawYamlResult()
fmt.Println(yaml)
}

const code = `
import kcl_plugin.hello

name = "kcl"
three = hello.add(1,2) # hello.add is written by Go
`

In KCL code, the hello plugin can be imported via import kcl_plugin.hello. The output result is

name: kcl
three: 3

2. Plugin Directory Structure

The KCL Go plugin is essentially a simple Go project, mainly containing the Go file api.go for the plugin code, which defines the registration and implementation functions of the plugin.

package hello_plugin

import (
"kcl-lang.io/kcl-go/pkg/plugin"
)

func init() {
plugin.RegisterPlugin(plugin.Plugin{
Name: "hello",
MethodMap: map[string]plugin.MethodSpec{
"add": {
Body: func(args *plugin.MethodArgs) (*plugin.MethodResult, error) {
v := args.IntArg(0) + args.IntArg(1)
return &plugin.MethodResult{V: v}, nil
},
},
},
})
}

3. Test Plugin

Write a file called api_test.go to perform unit testing on plugin functions.

package hello_plugin

import (
"testing"

"kcl-lang.io/kcl-go/pkg/plugin"
)

func TestPluginAdd(t *testing.T) {
result_json := plugin.Invoke("kcl_plugin.hello.add", []interface{}{111, 22}, nil)
if result_json != "133" {
t.Fatal(result_json)
}
}

Use Python to Write Plugins

0. Prerequisites

Using the KCL Python plugin requires the presence of Python 3.7+ in your PATH, install the KCL python SDK and set the plugin path.

python3 -m pip install kclvm
alias kcl-plugin="python3 -m kclvm.tools.plugin"
export KCL_PLUGINS_ROOT=~/.kcl/plugins

1. Hello Plugin

KCL plugins are installed in the plugins subdirectory of KCL (usually installed in the $HOME/.kcl/plugins directory), or set through the $KCL_PLUGINS_ROOT environment variable. Besides, the plugins directory could also be placed at the pwd path. KCL plugins are managed in the Git repository: https://github.com/kcl-lang/kcl-plugin, we can clone the repository for development.

Enter the kcl-plugin info command to view the plugin directory (replace /Users/kcl_user with the local $HOME path):

$ kcl-plugin info
# plugin_root: /Users/kcl_user/.kcl/plugins

View the list of plugins with the kcl-plugin list subcommand:

$ kcl-plugin list
hello: hello doc - 0.0.1

Where hello is an example builtin plugin (do not modify the plugin).

In KCL code, the hello plugin can be imported via import kcl_plugin.hello. main.k code is as follows:

import kcl_plugin.hello

name = "kcl"
three = hello.add(1,2)

The output result is

$ python3 -m kclvm main.k
name: kcl
three: 3

2. kcl-plugin Command

kcl-plugin is a plugin helper command line tool, the command line help is as follows:

$ kcl-plugin
usage: kcl-plugin [-h] {list,info,init,gendoc,test} ...
positional arguments:
{list,info,init,gendoc,test}
kcl plugin sub commands
list list all plugins
info show plugin document
init init a new plugin
gendoc gen all plugins document
test test plugin
optional arguments:
-h, --help show this help message and exit
  • The list subcommand is used to view the list of plugins.
  • The info subcommand is used to view the plugin directory and information about each plugin.
  • The init subcommand is used to initialize new plugins.
  • The gendoc subcommand is used to update the API documentation of all plugins.
  • The test subcommand is used to test specified plugins.

3. Plugin Information and Documentation

Enter kcl-plugin info hello to view the hello plugin information:

$ kcl-plugin info hello
{
"name": "hello",
"describe": "hello doc",
"long_describe": "long describe",
"version": "0.0.1",
"method": {
"add": "add two numbers, and return result",
"foo": "no doc",
"list_append": "no doc",
"say_hello": "no doc",
"tolower": "no doc",
"update_dict": "no doc"
}
}

The information of the plugin mainly includes the name and version information of the plugin, and the function information provided by the plugin. This information is consistent with the automatically generated api.md file in the plugin directory (regenerate the api.md file for all plugins via kcl-plugin gendoc when the plugin API document changes).

4. Plugin Directory Structure

The directory structure of the plugin is as follows (replace /Users/kcl_user with the local $HOME path):

$ tree /Users/kcl_user/.kcl/plugins/
/Users/kcl_user/.kcl/plugins/
├── _examples
├── _test
└── hello
├── api.md
├── plugin.py
└── plugin_test.py
$

The _examples directory is the sample code of the plugin, the _test directory is the KCL test code of the plugin, and the other directories starting with letters are ordinary plugins. The content of the plugin is as follows:

$ cat ./hello/plugin.py
# Copyright 2020 The KCL Authors. All rights reserved.
INFO = {
'name': 'hello',
'describe': 'hello doc',
'long_describe': 'long describe',
'version': '0.0.1',
}
def add(a: int, b: int) -> int:
"""add two numbers, and return result"""
return a + b
...

Where INFO specifies the name of the plugin, a brief description, a detailed description and version information. And all the functions whose names start with letters are the functions provided by the plugin, so the add function can be called directly in KCL.

Note: KCL plugins are implemented in an independent pure Python code file, and plugins cannot directly call each other.

5. Create Plugin

A plugin can be created with the kcl-plugin init command:

$ kcl-plugin init hi
$ kcl-plugin list
hello: hello doc - 0.0.1
hi: hi doc - 0.0.1

The kcl-plugin init command will construct a new plugin from the built-in template, and then we can view the created plugin information with the kcl-plugin list command.

6. Remove Plugin

KCL plugins are located in the plugins subdirectory of KCL (usually installed in the $HOME/.kcl/plugins directory). We can query the plugin installation directory with the command kcl-plugin info.

$ kcl-plugin info
/Users/kcl_user/.kcl/plugins/
$ tree /Users/kcl_user/.kcl/plugins/
/Users/kcl_user/.kcl/plugins/
├── _examples
├── _test
└── hello -- Delete this directory to delete the hello plugin
├── api.md
├── plugin.py
└── plugin_test.py
$

7. Test Plugin

There is a plugin_test.py file in the plugin directory, which is the unit test file of the plugin (based on the pytest testing framework). Also placed in the _test directory are plugin integration tests for KCL files. The plugin_test.py unit test is required, and the KCL integration tests in the _test directory can be added as needed.

Unit tests for plugins can be executed via kcl-plugin test:

$ kcl-plugin test hello
============================= test session starts ==============================
platform darwin -- Python 3.7.6+, pytest-5.3.5, py-1.9.0, pluggy-0.13.1
rootdir: /Users/kcl_user
collected 5 items
.kcl/plugins/hello/plugin_test.py ..... [100%]
============================== 5 passed in 0.03s ===============================
$

Integration tests can be tested by executing the python3 -m pytest command in the _test directory.