Initial Release
Template project with various Python code to be used with InterSystems IRIS community Edition docker container.
Featuring :
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:
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.
Open /src/ObjectScript/Embedded/Python.cls class and try to make changes - it will be compiled in running IRIS docker container.
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.
Then configure your python interpreter to /usr/irissys/bin/irispython
Open this url : http://localhost:8888/tree
Then you have access to three different notebooks with three different kernels.
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.
Settings file to let you immedietly code in VSCode with VSCode ObjectScript plugin
Config file if you want to debug with VSCode ObjectScript
Read about all the files in this article
Recommendation file to add extensions if you want to run with VSCode in the container.
This is very useful to work with embedded python.
This folder is devied in two parts, one for ObjectScript example and one for Python code.
Different piece of code that shows how to use python in IRIS.
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")
}
}
set demo = ##class(ObjectScript.Embbeded.Python).%New()
zw demo.DemoPyhtonToPython()
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>
}
}
Different piece of python code that shows how to use embedded python in IRIS.
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
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.
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
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:
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:
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.
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/
Three notebooks with three different kernels :
Notebooks can be access here http://localhost:8888/tree
This notebook uses IRIS embedded python kernel.
It shows example to open and save persistent classes and how to run sql queries.
This notebook uses vanilla python kernel.
It shows example run iris native apis.
This notebook uses ObjectScript kernel.
It shows example to run ObjectSCript code and how to use embedded pythoon in ObjectScript.
Initial Release