iris-python-examples

Downloads52
Subscribe
2
Bookmark
2
This application is not supported by InterSystems Corporation. Please be notified that you use it at your own responsibility.
Details
Releases
Reviews
Issues

What's new in this version

Initial Release

1. iris-python-template

Template project with various Python code to be used with InterSystems IRIS community Edition docker container.

Featuring :

  • Notebooks
    • Embedded Python Kernel
    • ObjectScript Kernel
    • Vanilla Python Kernel
  • Embedded Python
    • Code example
    • Flask demo
  • IRIS Python Native APIs
    • Code example

Diagram

2. Table of Contents

3. Installation

3.1. Docker

The repo is dockerised so you can clone/git pull the repo into any local directory

git clone https://github.com/grongierisc/iris-python-template.git

Open the terminal in this directory and run:

docker-compose up -d

and open then http://localhost:8888/tree for Notebooks

Or, open the cloned folder in VSCode, start docker-compose and open the URL via VSCode menu: VsCodeNotebooks

4. How to start coding

4.1. Prerequisites

Make sure you have git and Docker desktop installed.

This repository is ready to code in VSCode with ObjectScript plugin. Install VSCode, Docker and ObjectScript plugin and open the folder in VSCode.

4.1.1. Start coding in ObjectScript

Open /src/ObjectScript/Embedded/Python.cls class and try to make changes - it will be compiled in running IRIS docker container.

4.1.2. Start coding with Embedded Python

The easiest way is to run VsCode in the container.

To attach to a Docker container, either select Remote-Containers: Attach to Running Container... from the Command Palette (kbstyle(F1)) or use the Remote Explorer in the Activity Bar and from the Containers view, select the Attach to Container inline action on the container you want to connect to.

Containers Explorer screenshot

Then configure your python interpreter to /usr/irissys/bin/irispython

PythonInterpreter

4.1.3. Start coding with Notebooks

Open this url : http://localhost:8888/tree

Then you have access to three different notebooks with three different kernels.

  • Embedded Python kernel
  • ObjectScript kernel
  • Vanilla python3 kernel

Notebooks

5. What's inside the repository

5.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.

5.2. .vscode/settings.json

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

5.3. .vscode/launch.json

Config file if you want to debug with VSCode ObjectScript

Read about all the files in this article

5.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.

5.5. src folder

This folder is devied in two parts, one for ObjectScript example and one for Python code.

5.5.1. src/ObjectScript

Different piece of code that shows how to use python in IRIS.

5.5.1.1. src/ObjectScript/Embedded/Python.cls

All comments are in french to let you impove your French skills too.

/// Embedded python example
Class ObjectScript.Embbeded.Python Extends %SwizzleObject
{

/// HelloWorld with a parameter
ClassMethod HelloWorld(name As %String = "toto") As %Boolean [ Language = python ]
{
print("Hello",name)
return True
}

/// Description
Method compare(modèle, chaine) As %Status [ Language = python ]
{
import re

# <span class="pl-v">compare</span> <span class="pl-v">la</span> <span class="pl-v">cha</span>î<span class="pl-v">ne</span> [<span class="pl-v">cha</span>î<span class="pl-v">ne</span>] <span class="pl-v">au</span> <span class="pl-v">mod</span>è<span class="pl-v">le</span> [<span class="pl-v">mod</span>è<span class="pl-v">le</span>]
# <span class="pl-v">affichage</span> <span class="pl-v">r</span>é<span class="pl-v">sultats</span>
<span class="pl-v">print</span>(<span class="pl-v">f</span><span class="pl-s"><span class="pl-pds">"</span>\nRésultats({chaine},{modèle})<span class="pl-pds">"</span></span>)
<span class="pl-v">match</span> = <span class="pl-v">re</span>.<span class="pl-e">match</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-v">chaine</span>)
<span class="pl-k">if</span> <span class="pl-v">match</span>:
    <span class="pl-v">print</span>(<span class="pl-v">match</span>.<span class="pl-e">groups</span>())
<span class="pl-k">else</span>:
    <span class="pl-v">print</span>(<span class="pl-v">f</span><span class="pl-s"><span class="pl-pds">"</span>La chaîne [{chaine}] ne correspond pas au modèle [{modèle}]<span class="pl-pds">"</span></span>)

}

/// Description
Method compareObjectScript(modèle, chaine) As %Status
{
w !,"Résultats("chaine","modèle")",!
set matcher=##class(%Regex.Matcher).%New(modèle)
set matcher.Text=chaine
if matcher.Locate() {
write matcher.GroupGet(1)
}
else {
w "La chaîne ["chaine"] ne correspond pas au modèle ["modèle"]"
}
}

/// Description
Method DemoPyhtonToPython() As %Status [ Language = python ]
{
# expression régulières en python
# récupérer les différents champs d'une chaîne
# le modèle : une suite de chiffres entourée de caractères quelconques
# on ne veut récupérer que la suite de chiffres
modèle = r"^.?(\d+).?$"

# <span class="pl-v">on</span> <span class="pl-v">confronte</span> <span class="pl-v">la</span> <span class="pl-v">cha</span>î<span class="pl-v">ne</span> <span class="pl-v">au</span> <span class="pl-v">mod</span>è<span class="pl-v">le</span>
<span class="pl-v">self</span>.<span class="pl-e">compare</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-s"><span class="pl-pds">"</span>xyz1234abcd<span class="pl-pds">"</span></span>)
<span class="pl-v">self</span>.<span class="pl-e">compare</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-s"><span class="pl-pds">"</span>12 34<span class="pl-pds">"</span></span>)
<span class="pl-v">self</span>.<span class="pl-e">compare</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-s"><span class="pl-pds">"</span>abcd<span class="pl-pds">"</span></span>)

}

Method DemoPyhtonToObjectScript() As %Status [ Language = python ]
{
# expression régulières en python
# récupérer les différents champs d'une chaîne
# le modèle : une suite de chiffres entourée de caractères quelconques
# on ne veut récupérer que la suite de chiffres
modèle = r"^.?(\d+).?$"

# <span class="pl-v">on</span> <span class="pl-v">confronte</span> <span class="pl-v">la</span> <span class="pl-v">cha</span>î<span class="pl-v">ne</span> <span class="pl-v">au</span> <span class="pl-v">mod</span>è<span class="pl-v">le</span>
<span class="pl-v">self</span>.<span class="pl-e">compareObjectScript</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-s"><span class="pl-pds">"</span>xyz1234abcd<span class="pl-pds">"</span></span>)
<span class="pl-v">self</span>.<span class="pl-e">compareObjectScript</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-s"><span class="pl-pds">"</span>12 34<span class="pl-pds">"</span></span>)
<span class="pl-v">self</span>.<span class="pl-e">compareObjectScript</span>(<span class="pl-v">mod</span>è<span class="pl-v">le</span>, <span class="pl-s"><span class="pl-pds">"</span>abcd<span class="pl-pds">"</span></span>)

}

/// Description
Method DemoObjectScriptToPython() As %Status
{
// le modèle - une date au format jj/mm/aa
set modèle = "^\s*(\d\d)/(\d\d)/(\d\d)\s*$"
do ..compare(modèle, "10/05/97")
do ..compare(modèle, " 04/04/01 ")
do ..compare(modèle, "5/1/01")
}

}

  • HelloWorld
    • Simple function to say Hello in python
    • It uses the OjectScript wrapper with the tag [ Language = python ]
  • compare
    • An python function that compare a string with a regx, if their is a match then print it, if not print that no match has been found
  • compareObjectScript
    • Same function as the python one but in ObjectScript
  • DemoPyhtonToPython
    • Show how to use a python function with python code wrapped in ObjectScript
set demo = ##class(ObjectScript.Embbeded.Python).%New()

zw demo.DemoPyhtonToPython()

  • DemoPyhtonToObjectScript
    • An python function who show how to call an ObjecScript function
  • DemoObjectScriptToPython
    • An ObjectScript function who show how to call an python function

5.5.1.2. src/ObjectScript/Gateway/Python.cls

An ObjectScript class who show how to call an external phyton code with the gateway functionnality.

In this example python code is not executed in the same process of IRIS.

/// Description
Class Gateway.Python
{

/// Demo of a python gateway to execute python code outside of an iris process.
ClassMethod Demo() As %Status
{
Set sc = $$$OK

<span class="pl-k">set</span> <span class="pl-v">pyGate</span> = <span class="pl-en">$system</span>.<span class="pl-e">external</span>.<span class="pl-e">getPythonGateway</span>()

<span class="pl-k">d</span> <span class="pl-v">pyGate</span>.<span class="pl-e">addToPath</span>(<span class="pl-s"><span class="pl-pds">"</span>/irisdev/app/src/Python/gateway/Address.py<span class="pl-pds">"</span></span>)

<span class="pl-k">set</span> <span class="pl-v">objectBase</span> = <span class="pl-k">##class</span>(<span class="pl-en">%Net.Remote.Object</span>).<span class="pl-e">%New</span>(<span class="pl-v">pyGate</span>,<span class="pl-s"><span class="pl-pds">"</span>Address<span class="pl-pds">"</span></span>)

<span class="pl-k">set</span> <span class="pl-v">street</span> = <span class="pl-v">objectBase</span>.<span class="pl-e">street</span>

<span class="pl-k">zw</span> <span class="pl-v">street</span>

<span class="pl-k">Return</span> <span class="pl-v">sc</span>

}

}

5.5.2. src/Python

Different piece of python code that shows how to use embedded python in IRIS.

5.5.2.1. src/Python/embedded/demo.cls

All comments are in french to let you impove your French skills too.

import iris

person = iris.cls('Titanic.Table.Passenger')._OpenId(1)

print(person.dict)

First import iris module that enable embedded python capabilities. Open an persistent class with cls function from iris module. Note that all % function are replaced with _.

To run this example you have to use iris python shell :

/usr/irissys/bin/irispython /opt/irisapp/src/Python/embedded/demo.py

5.5.2.2. src/Python/native/demo.cls

Show how to use native api in python code.

import irisnative

# create database connection and IRIS instance
connection = irisnative.createConnection("localhost", 1972, "USER", "superuser", "SYS", sharedmemory = False)
myIris = irisnative.createIris(connection)

# classMethod
passenger = myIris.classMethodObject("Titanic.Table.Passenger","%OpenId",1)
print(passenger.get("name"))

# global
myIris.set("hello","myGlobal")
print(myIris.get("myGlobal"))

To import irisnative, you have to install the native api wheels in your python env.

pip3 install /usr/irissys/dev/python/intersystems_irispython-3.2.0-py3-none-any.whl

Then you can run this python code

/usr/bin/python3 /opt/irisapp/src/Python/native/demo.py

Note that in this case a connection is made to iris database, this mean, this code is executed in a different thread than the IRIS one.

5.5.2.3. src/Python/flask

A full demo of the combiantion between embedded python and the micro framework flask. You can test this end point :

GET http://localhost:4040/api/passengers?currPage=1&pageSize=1
5.5.2.3.1. How it works

In order to use embedded Python, we use irispython as a python interepreter, and do:

import iris

Right at the beginning of the file.

We will then be able to run methods such as:

flaskExample

As you can see, in order to GET a passenger with an ID, we just execute a query and use its result set.

We can also directly use the IRIS objects:

flaskObjectExample

Here, we use an SQL query to get all the IDs in the table, and we then retreive each passenger from the table with the %OpenId() method from the Titanic.Table.Passenger class (note that since % is an illegal character in Python, we use _ instead).

Thanks to Flask, we implement all of our routes and methods that way.

5.5.2.3.2. Launching the flask server

To launch the server, we use gunicorn with irispython.

In the docker-compose file, we add the following line:

iris:
  command: -a "sh /opt/irisapp/server_start.sh"

That will launch, after the container is started (thanks to the -a flag), the following script:

#!/bin/bash

cd ${SRC_PATH}/src/Python/flask

${PYTHON_PATH} -m gunicorn --bind "0.0.0.0:8080" wsgi:app &

exit 1

With the environment variables defined in the Dockerfile as follows:

ENV PYTHON_PATH=/usr/irissys/bin/irispython
ENV SRC_PATH=/opt/irisapp/

5.5.3. src/Notebooks

Three notebooks with three different kernels :

  • One Python3 kernel to run native APIs
  • One Embedded Python kernel
  • One ObjectScript kernel

Notebooks can be access here http://localhost:8888/tree

Notebooks

5.5.3.1. src/Notebooks/HelloWorldEmbedded.ipynb

This notebook uses IRIS embedded python kernel.

It shows example to open and save persistent classes and how to run sql queries.

5.5.3.2. src/Notebooks/IrisNative.ipynb

This notebook uses vanilla python kernel.

It shows example run iris native apis.

5.5.3.3. src/Notebooks/ObjectScript.ipynb

This notebook uses ObjectScript kernel.

It shows example to run ObjectSCript code and how to use embedded pythoon in ObjectScript.

Rating
5 (1)
Category
Developer Environment
Works with
InterSystems IRIS
Tags
Info
Version
1.0.0
Last updated
2021-12-13
Repository
Open
Documentation
Open
License
Link