Home Applications interoperability-embedded-python

interoperability-embedded-python

This application is not supported by InterSystems Corporation. Please be notified that you use it at your own risk.
5
15 reviews
0
Awards
7.5k
Views
1.1k
IPM installs
12
12
Details
Releases
Reviews  (15)
Issues
Pull requests  (1)
Articles  (10)
Hack of PEX Python but for Embedded Python

What's new in this version

Enhancement :

  • Support of async function in BP and BO.
  • Support of multi sync call
  • Trace option in log

Fix:

  • Better support of retro-compatibility of gronngier.pex

1. interoperability-embedded-python

This proof of concept aims to show how the iris interoperability framework can be use with embedded python.

1.1. Table of Contents

1.2. Example

import grongier.pex
import iris
import MyResponse

class MyBusinessOperation(grongier.pex.BusinessOperation):
    
    def OnInit(self):
        #OnInit method has it exists in objectscript
        #This method is called when the component is becoming active in the production
        print("[Python] ...MyBusinessOperation:OnInit() is called")
        self.LOGINFO("Operation OnInit")
        return

    def OnTeardown(self):
        #OnTeardown method has it exists in objectscript
        #This method is called when the component is becoming inactive in the production
        print("[Python] ...MyBusinessOperation:OnTeardown() is called")
        return

    def OnMessage(self, messageInput):
        # called from ticker service, message is of type MyRequest with property requestString
        print("[Python] ...MyBusinessOperation:OnMessage() is called with message:"+messageInput.requestString)
        self.LOGINFO("Operation OnMessage")
        response = MyResponse.MyResponse("...MyBusinessOperation:OnMessage() echos")
        return response

1.3. Regsiter a component

No ObjectScript code is needed.

Thanks to the method Grongier.PEX.Utils.RegisterComponent() :

Start an embedded python shell :

/usr/irissys/bin/irispython

Then use this class method to add a new py file to the component list for interoperability.

iris.cls("Grongier.PEX.Utils").RegisterComponent(<ModuleName>,<ClassName>,<PathToPyFile>,<OverWrite>,<NameOfTheComponent>)

e.g :

iris.cls("Grongier.PEX.Utils").RegisterComponent("MyCombinedBusinessOperation","MyCombinedBusinessOperation","/irisdev/app/src/python/demo/",1,"PEX.MyCombinedBusinessOperation")

This is a hack, this not for production.

2. Demo

The production has four component in pure python :

  • Two Business Services :
    • Grongier.PEX.MyCombinedBusinessService, which sent continually sync messages to an business operation
      • Thoses messages are python objects cast JSON and stored in Grongier.PEX.Message.
      • Python code : src/python/demo/MyCombinedBusinessService.py
    • Grongier.PEX.MyBusinessService, who basically does nothing, it's a raw business service who writes message logs
      • Python code : src/python/demo/MyBusinessService.py
  • Two Business Operations :
    • Grongier.PEX.BusinessOperation, which receive message from Grongier.PEX.MyCombinedBusinessService
      • Python code : src/python/demo/MyBusinessOperation.py
    • Grongier.PEX.CombinedBusinessOperation, it can receive Ens.StringRequest message and response with Ens.StringResponse
      • Python code : src/python/demo/MyCombinedBusinessOperation.py
interop-screenshot

New json trace for python native messages :

json-message-trace

3. Prerequisites

Make sure you have git and Docker desktop installed.

4. Installation with Docker

Clone/git pull the repo into any local directory

git clone https://github.com/grongierisc/interpeorability-embedded-python

Open the terminal in this directory and run:

docker-compose build

Run the IRIS container with your project:

docker-compose up -d

5. Installation without Docker

Install the grongier_pex-1.0.0-py3-none-any.whl on you local iris instance :

/usr/irissys/bin/irispython -m pip install grongier_pex-1.0.0-py3-none-any.whl

Then load the ObjectScript classes :

do $System.OBJ.LoadDir("/opt/irisapp/src","cubk","*.cls",1)

6. How to Run the Sample

Open the production and start it.
It will start running some code sample.

7. What's inside the repository

7.1. Dockerfile

A dockerfile which install some python dependancies (pip, venv) and sudo in the container for conviencies.
Then it create the dev directory and copy in it this git repository.

It starts IRIS and imports Titanics csv files, then it activates %Service_CallIn for Python Shell.
Use the related docker-compose.yml to easily setup additional parametes like port number and where you map keys and host folders.

This dockerfile ends with the installation of requirements for python modules.

The last part is about installing jupyter notebook and it's kernels.

Use .env/ file to adjust the dockerfile being used in docker-compose.

7.2. .vscode/settings.json

Settings file to let you immedietly code in VSCode with VSCode ObjectScript plugin

7.3. .vscode/launch.json

Config file if you want to debug with VSCode ObjectScript

Read about all the files in this article

7.4. .vscode/extensions.json

Recommendation file to add extensions if you want to run with VSCode in the container.

More information here

Archiecture

This is very useful to work with embedded python.

7.5. src folder

src
├── Grongier
│   └── PEX // ObjectScript classes that wrap python code
│       ├── BusinessOperation.cls
│       ├── BusinessProcess.cls
│       ├── BusinessService.cls
│       ├── Common.cls
│       ├── Director.cls
│       ├── InboundAdapter.cls
│       ├── Message.cls
│       ├── OutboundAdapter.cls
│       ├── Python.cls
│       ├── Test.cls
│       └── Utils.cls
├── PEX // Some example of wrapped classes
│   ├── MyBusinessOperationWithAdapter.cls
│   ├── MyBusinessOperationWithIrisAdapter.cls
│   ├── MyBusinessOperationWithPythonAdapter.cls
│   ├── MyBusinessService.cls
│   ├── MyOutboundAdapter.cls
│   └── Production.cls
└── python
    ├── demo // Actual python code to rnu this demo
    │   ├── MyBusinessOperation.py
    │   ├── MyBusinessOperationWithAdapter.py
    │   ├── MyBusinessOperationWithIrisAdapter.py
    │   ├── MyBusinessProcess.py
    │   ├── MyBusinessService.py
    │   ├── MyCombinedBusinessOperation.py
    │   ├── MyCombinedBusinessProcess.py
    │   ├── MyCombinedBusinessService.py
    │   ├── MyInboundAdapter.py
    │   ├── MyLoggingOperation.py
    │   ├── MyNonPollingStarter.py
    │   ├── MyOutboundAdapter.py
    │   ├── MyRequest.py
    │   ├── MyResponse.py
    │   ├── MySyncBusinessProcess.py
    │   └── SimpleObject.py
    ├── dist // Wheel used to implement python interoperability components
    │   └── grongier_pex-1.0.0-py3-none-any.whl
    ├── grongier
    │   └── pex // Helper classes to implement interoperability components
    │       ├── _BusinessHost.py
    │       ├── _BusinessOperation.py
    │       ├── _BusinessProcess.py
    │       ├── _BusinessService.py
    │       ├── _Common.py
    │       ├── _Director.py
    │       ├── _InboundAdapter.py
    │       ├── _Message.py
    │       ├── _OutboundAdapter.py
    │       └── __init__.py
    └── setup.py // setup to build the wheel

8. How to add a new component

8.1. InboundAdapter

To implement InboundAdapter in Python, users do the following:

Subclass from grongier.pex.InboundAdapter in Python. Override method OnTask().

8.2. OutboundAdapter

To implement OutboundAdapter in Python, users do the following:

Subclass from grongier.pex.OutboundAdapter in Python. Implement required action methods.

8.3. BusinessService

To implement BusinessService in Python, users do the following:

Subclass from grongier.pex.BusinessService in Python. Override method OnProcessInput().

8.4. BusinessProcess

To implement BusinessProcess in Python, users do the following:

Subclass from grongier.pex.BusinessProcess in Python. Override methods OnRequest(), OnResponse() and OnComplete().

8.5. BusinessOperation

To implement BusinessOperation in Python, users do the following:

Subclass from grongier.pex.BusinessOperation in Python. Override method OnMessage().

8.6. Regsiter a component

Start an embedded python shell :

/usr/irissys/bin/irispython

Then use this class method to add a new py file to the component list for interoperability.

iris.cls("Grongier.PEX.Utils").RegisterComponent(<ModuleName>,<ClassName>,<PathToPyFile>,<OverWrite>,<NameOfTheComponent>)

e.g :

iris.cls("Grongier.PEX.Utils").RegisterComponent("MyCombinedBusinessOperation","MyCombinedBusinessOperation","/irisdev/app/src/python/demo/",1,"PEX.MyCombinedBusinessOperation")

8.7. Direct use of Grongier.PEX

If you don't want to use the RegisterComponent util. You can add an Grongier.PEX.Business* component and configure the properties :

  • %module :
    • Module name of your python code
  • %classname :
    • Classname of you component
  • %classpaths
    • Path where you component is.
      • This can one or more Classpaths (separated by '|' character) needed in addition to PYTHON_PATH

e.g :

component-config

9. Future work

  • Only Service and Operation has been tested.
  • Work in progress on adapter

10. Credits

Most of the code came from PEX for Python by Mo Cheng and Summer Gerry.

The register part is from the not released feature form IRIS 2021.3.

Made with
Install
zpm install pex-embbeded-python download archive
Version
3.1.026 Jul, 2024
Ideas portal
https://ideas.intersystems.com/ideas/DP-I-143
Category
Developer Environment
Works with
InterSystems IRIS
First published
03 Jan, 2022
Last checked by moderator
18 Jun, 2024Works