Python adapter via callout for InterSystems Data Platforms.
- Load ObjectScript code (i.e.
do $system.OBJ.LoadDir("C:\InterSystems\Repos\Python\isc\py\","*.cls",,1)
). - Place callout DLL/SO/DYLIB in the
bin
folder of your InterSystems IRIS installation. Library file should be placed into a path returned bywrite ##class(isc.py.Callout).GetLib()
.
- Check that your
PYTHONHOME
environment variable points to Python 3.6. - Check that your SYSTEM
PATH
environment variable hasPYTHONHOME
variable (or directory it points to).
- Check that your SYSTEM
PATH
environment variable has/usr/lib
and/usr/lib/x86_64-linux-gnu
, preferably at the begining. Use/etc/environment
file to set environment variables.
If you modified environment variables restart your InterSystems product.
- Call:
set sc = ##class(isc.py.Callout).Setup()
once per systems start (add to ZSTART: docs, sample). - Call main method (can be called many times, context persists):
write ##class(isc.py.Main).SimpleString(code, variable, , .result)
- Call:
set sc = ##class(isc.py.Callout).Finalize()
to free Python context. - Call:
set sc = ##class(isc.py.Callout).Unload()
to free callout library.
set sc = ##class(isc.py.Callout).Setup()
set sc = ##class(isc.py.Main).SimpleString("x='HELLO'", "x", , .x)
write x
set sc = ##class(isc.py.Callout).Finalize()
set sc = ##class(isc.py.Callout).Unload()
Generally the main interface to Python is isc.py.Main
. It offers these methods (all return %Status
):
SimpleString(code, returnVariable, serialization, .result)
- for cases where both code and variable are strings.ExcuteCode(code, variable)
- executecode
(it may be a stream or string), optionally ser result intovariable
.GetVariable(variable, serialization, .stream, useString)
- getserialization
ofvariable
instream
. IfuseString
is 1 and variable serialization can fit into string then string is returned instead of the stream.GetVariableInfo(variable, serialization, .defined, .type, .length)
- get info about variable: is it defined, type,and serialization length.GetStatus()
- returns last occured exception in Python and clears it.GetVariableJson(variable, .stream, useString)
- get JSON serialization of variable.GetVariablePickle(variable, .stream, useString)
- get Pickle serialization of variable.ExecuteQuery(query, variable, type)
- create resultset (pandasdataframe
orlist
) from sql query and set it intovariable
.ImportModule(module, .imported, .alias)
- import module with alias.GetModuleInfo(module, .imported, .alias)
- get module alias and is it currently imported.
Possible Serializations:
##class(isc.py.Callout).SerializationStr
- Serialization by str() function##class(isc.py.Callout).SerializationRepr
- Serialization by repr() function
Python context can be persisted into InterSystems IRIS and restored later on. There are currently three public functions:
- Save context:
set sc = ##class(isc.py.data.Context).SaveContext(.context, maxLength, mask, verbose)
wheremaxLength
- maximum length of saved variable. If veriable serialization is longer than that, it would be ignored. Set to 0 to get them all,mask
- comma separated list of variables to save (special symbols * and ? are recognized),verbose
specifies displaying context after saving, andcontext
is a resulting Python context. Get context id withcontext.%Id()
- Display context:
do ##class(isc.py.data.Context).DisplayContext(id)
whereid
is an id of a stored context. Leave empty to display current context. - Restore context:
do ##class(isc.py.data.Context).RestoreContext(id, verbose, clear)
whereclear
kills currently loaded context if set to 1.
Context is saved into isc.py.data
package and can be viewed/edited by SQL and object methods.
Interoperability adapter isc.py.ens.Operation
offers abulity to interact with Python process from Interoperability productions. Currently three operations are supported:
- Execute Python code via
isc.py.msg.ExecutionRequest
. Returnsisc.py.msg.ExecutionResponse
with requested variable values - Execute Python code via
isc.py.msg.StreamExecutionRequest
. Returnsisc.py.msg.StreamExecutionResponse
with requested variable values. Same as above, but accepts and returns streams instead of strings. - Set dataset from SQL Query with
isc.py.msg.QueryRequest
. ReturnsEns.Response
. - Save Python conext via
isc.py.msg.SaveRequest
. ReturnsEns.StringResponse
with context id. - Restore Python context via
isc.py.msg.RestoreRequest
.
Check request/response classes documentation for details.
Along with callout code and Interoperability adapter there's also a test Interoperability Production and test Business Process. To use them:
- In OS bash execute
pip install pandas matplotlib seaborn
. - Execute:
do ##class(isc.py.test.CannibalizationData).Import()
to populate test data. - Create ODBC or JDBC connection to the namespace with data.
- In test Business Process
isc.py.test.Process
edit annotation forODBC connection
orJDBC connection
call, specifying correct DSN. - Edit annotation for
Correlation Matrix: Graph
call, specifying valid filepath forf.savefig
function. - Save and compile business process.
- Configure
ConnectionType
setting for a business process. - Start
isc.py.test.Production
production. - Send empty
Ens.Request
mesage to theisc.py.test.Process
.
Notes.
- If you want to use
ODBC
connection, install pyodbc:pip install pyodbc
. - For ODBC on Linux insall
unixodbc unixodbc-dev python-pyodbc
. - If you want to use
JDBC
connection, install JayDeBeApi:pip install JayDeBeApi
. On linux you might need to installapt-get install python-apt
. - If you get errors similar to
undefined symbol: _Py_TrueStruct
inisc.py.ens.Operation
operation set settingPythonLib
tolibpython3.6m.so
or even to a full path of the shared library.
To run tests execute:
set repo = ##class(%SourceControl.Git.Utils).TempFolder()
set ^UnitTestRoot = ##class(%File).SubDirectoryName(##class(%File).SubDirectoryName(##class(%File).SubDirectoryName(repo,"isc"),"py"),"unit",1)
set sc = ##class(%UnitTest.Manager).RunTest(,"/nodelete")
There are several limitaions associated with the use of PythonAdapter.
- Modules reinitialization. Some modules may only be loaded once diring process lifetime (i.e. numpy). While Finalization clears the context of the process, repeated load of such libraries terminates the process. Discussions: 1, 2.
- Variables. Do not use these variables:
zzzcolumns
,zzzdata
,zzzdef
,zzzalias
,zzzerr
,zzzvar
,zzztype
,zzzlen
,zzzjson
,zzzpickle
,zzzcount
,zzzitem
,zzzmodules
,zzzvars
. Please report any leakage of these variables. System code should always clear them. - Functions Do not redefine these functions
zzzmodulesfunc()
,zzzvarsfunc()
,zzzgetalias()
,zzzempty()
. - Context persistence. Only pickled variables could be restored correctly. User functions are currently not supported. Module imports are supported.
Development of ObjectScript is done via cache-tort-git in UDL mode. Development of C code is done in Eclipse.
- Install MinGW-w64 you'll need
make
andgcc
. - Rename
mingw32-make.exe
tomake.exe
inmingw64\bin
directory. - Set
GLOBALS_HOME
environment variable to the root of Caché or Ensemble installation. - Set
PYTHONHOME
environment variable to the root of Python3 installation. UsuallyC:\Users\<User>\AppData\Local\Programs\Python\Python3<X>
- Open MinGW bash (
mingw64env.cmd
). - In
<Repository>\c\
executemake
.
- Add Python 3.6 repo:
add-apt-repository ppa:jonathonf/python-3.6
andapt-get update
- Install:
apt install python3.6 python3.6-dev libpython3.6-dev build-essential
- Set
GLOBALS_HOME
environment variable to the root of Caché or Ensemble installation. - Set environment variable
PYTHONVER
to the python version you want to build, i.e.:export PYTHONVER=3.6
- In
<Repository>/c/
executemake
.
- Install Python 3.6 and gcc compiler.
- Set
GLOBALS_HOME
environment variable to the root of Caché or Ensemble installation. - Set environment variable
PYTHONVER
to the python version you want to build, i.e.:export PYTHONVER=3.6
- In
<Repository>/c/
execute:
gcc -Wall -Wextra -fpic -O3 -fno-strict-aliasing -Wno-unused-parameter -I/Library/Frameworks/Python.framework/Versions/${PYTHONVER}/Headers -I${GLOBALS_HOME}/dev/iris-callin/include -c -o iscpython.o iscpython.c
gcc -dynamiclib -L/Library/Frameworks/Python.framework/Versions/${PYTHONVER}/lib -L/usr/lib -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker iscpython.o -o iscpython.dylib
If you have a Mac please update makefile so we can build Mac version via Make.