--- title: Plugins keywords: fastai sidebar: home_sidebar nb_path: "nbs/plugin.pluginbase.ipynb" ---
{% raw %}
{% endraw %} {% raw %}
{% endraw %}

PluginBase is the plugin class that the simplest plugin inherits.

Inheriting class should implement:

  • run() that implements the logic of the plugin
  • add_to_schema() for plugin specific item types
{% raw %}
{% endraw %}

Creating a plugin

The memri pod uses a plugin system to add features to the backend memri backend. Plugins can import your data (importers), change your data (indexers), or call other serivces. Users can define their own plugins to add new behaviour to their memri app. Let's use the following plugin as an example of how we can start plugins.

{% raw %}
class MySimplePlugin(PluginBase):
    """"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def run(self):
        print("running")
        items = self.client.search({'type': 'MyItem'})
        for item in items:
            if item.age > 65:
                item.name = f"Sr. {item.name}"
            if item.age <= 18:
                item.name = f"Jr. {item.name}"

    def add_to_schema(self):
        self.client.add_to_schema(MyItem("my name", 10))
{% endraw %}

More Complex Plugin Examples (with authentication)

class ExampleOAuthAuthenticator(OAuthAuthenticator):

    def get_oauth_url(self):
        return "https://example.com/oauth"

    def get_tokens_from_code(self, code):
        return {
            'access_token': 'dummy_access_token_with_' + code,
            'refresh_token': 'dummy_refresh_token'
        }

    def refresh_tokens(self, refreshToken):
        return {
            'access_token': 'refreshed_dummy_access_token',
            'refresh_token': 'refreshed_dummy_refresh_token'
        }

    def get_api_instance(self):
        return MyAPIClient(self.pluginRun.account[0].secret)


class ExamplePasswordAuthenticator(PasswordAuthenticator):

    SERVICE_URL = "https://example.com/login"
    def get_token(self, username, password):
        result = requests.post(self.SERVICE_URL, {'username': username, 'password': password})
        if result.status_code == 200:
            try:
                res = result.json()
                return res['session_token']
            except:
                pass
class MyAPIClient:
    def __init__(self, accessToken):
        self.access_token = accessToken

    def get_data(self):
        return [{'name': 'name_1', 'age': 21}, {'name': 'name_2', 'age': 22}]



class MyItem(Item):
    properties = Item.properties + ["name", "age"]
    edges = Item.edges
    def __init__(self, name=None, age=None, **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.age = age

class MyOAuthPlugin(PluginBase):
    """"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def run(self):
        print("running")
        self.login()
        items = self.api.get_data()
        for item in items:
            self.client.create(MyItem(name=item['name'], age=item['age']))

    def login(self):
        auth = ExampleOAuthAuthenticator(self.client, self.pluginRun)
        # auth.isTest = True # for testing
        auth.authenticate()
        self.api = MyAPIClient(self.pluginRun.account[0].secret)

    def add_to_schema(self):
        self.client.add_to_schema(MyItem("my name", 10))


class MyPasswordPlugin(PluginBase):
    """"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def run(self):
        print("running")
        self.login()
        items = self.api.get_data()
        for item in items:
            self.client.create(MyItem(name=item['name'], age=item['age']))

    def login(self):
        auth = PasswordAuthenticator(self.client, self.pluginRun)
        auth.isTest = True
        token = auth.authenticate()
        self.api = MyAPIClient(token)

    def add_to_schema(self):
        self.client.add_to_schema(MyItem("my name", 10))

Memri plugins need to define at least 2 methods: .run() and .add_to_schema(). .run() defines the logic of the plugin. .add_to_schema() defines the schema for the plugin in the pod. Note that currently, add_to_schema requires all item to have all properties defined that are used in the plugin. In the future, we might replace add_to_schema, to be done automatically, based on a declarative schema defined in the plugin.

Test Plugin Runtime

Running your plugin using the CLI

Plugins can be started using the pymemri run_plugin or simulate_run_plugin_from_frontend CLI. With run_plugin the plugin is invoked directly by spawning a new python process, while simulate_run_plugin_from_frontend requests the pod to spawn a new process, docker container, or kubernetes container, which in calls run_plugin (for more info see simulate_run_plugin_from_frontend. When using run_plugin, you can either pass your run arguments as parameters, or set them as environment variables. If both are set, the CLI will use the passed arguments.

{% raw %}

run_plugin[source]

run_plugin(pod_full_address:Param object at 0x7f35d470dd90>='http://localhost:3030', plugin_run_id:Param object at 0x7f35d470ddc0>=None, database_key:Param object at 0x7f35d470dcd0>=None, owner_key:Param object at 0x7f35d470dc70>=None, read_args_from_env:Param object at 0x7f35d470dd60>=False, config_file:Param object at 0x7f35d470dd30>=None)

{% endraw %} {% raw %}
{% endraw %}

To start a plugin on your local machine, you can use the CLI. This will create a client for you, and run the code defined in <myplugin>.run()

{% raw %}
run_plugin(config_file="../example_config.json")
reading database_key from /Users/koen/.pymemri/pod_keys/keys.json
reading owner_key from /Users/koen/.pymemri/pod_keys/keys.json
pod_full_address=http://localhost:3030
owner_key=8677996173299944016776856689234978705539171358808241281853139489

running
logging in with account myusername and password mypassword
{% endraw %}

{% include note.html content='The data that is created here should be in the pod in order for this to work' %}

Run from pod

In production, we start plugins by making an API call to the pod, which in turn creates an environment for the plugin and starts it using docker containers, kubernetes containers or a shell script. We can start this process using the simulate_run_plugin_from_frontend CLI. Note that when using docker, provided container name should be "installed" within the Pod environemnt (e.g. docker build -t pymemri . for this repo) in order to start it.

running a plugin

{% raw %}

simulate_run_plugin_from_frontend[source]

simulate_run_plugin_from_frontend(pod_full_address:"The pod full address"='http://localhost:3030', database_key:"Database key of the pod"=None, owner_key:"Owner key of the pod"=None, container:"Pod container to run frod"=None, plugin_path:"Plugin path"=None, settings_file:"Plugin settings (json)"=None, config_file:"config file for the PluginRun"=None, account_id:"Account id to be used inside the plugin"=None)

{% endraw %} {% raw %}
{% endraw %} {% raw %}
client = PodClient()
{% endraw %} {% raw %}
!simulate_run_plugin_from_frontend --config_file="../example_config.json"
reading database_key from /Users/koen/.pymemri/pod_keys/keys.json
reading owner_key from /Users/koen/.pymemri/pod_keys/keys.json
pod_full_address=http://localhost:3030
owner_key=8677996173299944016776856689234978705539171358808241281853139489

calling the `create` api on http://localhost:3030 to make your Pod start a plugin with id 4DfDBbcdcbABcf822Fc7DC5d5b3C3BDc.
*Check the pod log/console for debug output.*
{% endraw %}