Skip to content

Commit 7f1e32d

Browse files
committed
# Conflicts: # sc-list.txt
2 parents 3165ab2 + 406541e commit 7f1e32d

15 files changed

+1055
-1
lines changed

.gitignore

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Object files
5+
*.o
6+
*.ko
7+
*.obj
8+
*.elf
9+
10+
# Linker output
11+
*.ilk
12+
*.map
13+
*.exp
14+
15+
# Precompiled Headers
16+
*.gch
17+
*.pch
18+
19+
# Libraries
20+
*.lib
21+
*.a
22+
*.la
23+
*.lo
24+
25+
# Shared objects (inc. Windows DLLs)
26+
*.dll
27+
*.so
28+
*.so.*
29+
*.dylib
30+
31+
# Executables
32+
*.exe
33+
*.out
34+
*.app
35+
*.i*86
36+
*.x86_64
37+
*.hex
38+
39+
# Debug files
40+
*.dSYM/
41+
*.su
42+
*.idb
43+
*.pdb
44+
45+
# Kernel Module Compile Results
46+
*.mod*
47+
*.cmd
48+
.tmp_versions/
49+
modules.order
50+
Module.symvers
51+
Mkfile.old
52+
dkms.conf

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 InterSystems
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# PythonAdapter
2+
Python adapter via callout for InterSystems Data Platforms.
3+
4+
# Installation
5+
6+
1. Load ObjectScript code.
7+
2. Place callout DLL in `bin` folder.
8+
3. Check that your `PYTHONHOME` environment variable points to Python 3.6.
9+
4. Check that your SYSTEM `PATH` environment variable has `PYTHONHOME` variable (or directory it points to).
10+
11+
# Use
12+
13+
1. Call: `do ##class(isc.py.Callout).Setup()` once per systems start (add to ZSTART!)
14+
2. Call: `do ##class(isc.py.Callout).Initialize()` once per process
15+
3. Call main method (can be called many times, context persists): `write ##class(isc.py.Callout).SimpleString(code, data)`
16+
4. Call: `do ##class(isc.py.Callout).Finalize()` to free Python context
17+
5. Call: `write ##class(isc.py.Callout).Unload()` to free callout library
18+
19+
```
20+
do ##class(isc.py.Callout).Setup()
21+
do ##class(isc.py.Callout).Initialize()
22+
write ##class(isc.py.Callout).SimpleString("x='ПРИВЕТ'","x")
23+
write ##class(isc.py.Callout).SimpleString("x=repr('ПРИВЕТ')","x")
24+
write ##class(isc.py.Callout).SimpleString("x=123","x")
25+
do ##class(isc.py.Callout).Finalize()
26+
write ##class(isc.py.Callout).Unload()
27+
```
28+
29+
# Test Business Process
30+
31+
Along with callout code and Interoperability adapter there's also a test Interoperability Production and test Business Process. To use them:
32+
33+
1. In OS bash execute `python -m pip install pyodbc pandas matplotlib seaborn`.
34+
2. Execute: `do ##class(isc.py.test.CannibalizationData).Import()` to populate test data.
35+
3. Create ODBC connection to the namespace with data
36+
4. In test Business Process `isc.py.test.Process` edit annotation for `Correlation Matrix: Tabular` call, specifying correct ODBC DSN in line 3
37+
5. Edit annotation for `Correlation Matrix: Graph` call, specifying valid filepath for `f.savefig` function.
38+
6. Save and compile business process.
39+
7. Start `isc.py.test.Production` production.
40+
8. Send empty `Ens.Request` mesage to the `isc.py.test.Process`.
41+
42+
43+
44+
# Development
45+
46+
Development of ObjectScript is done via [cache-tort-git](https://github.com/MakarovS96/cache-tort-git) in UDL mode.
47+
Development of C code is done in Eclipse.

c/Makefile

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
CC := gcc
2+
RM := rm
3+
CD := cd
4+
MAKE := make
5+
6+
CFLAGS += -Wall -Wextra -fpic -O2 -fno-strict-aliasing -Wno-unused-parameter
7+
8+
9+
SYS := $(shell gcc -dumpmachine)
10+
11+
ifeq ($(SYS), x86_64-w64-mingw32)
12+
BUILDSYS := $(SYS)
13+
else
14+
BUILDSYS := $(shell bash $(LIBFFI_PATH)/config.guess)
15+
endif
16+
17+
ifneq (, $(findstring linux, $(SYS)))
18+
SUFFIX := so
19+
LDFLAGS := -shared
20+
LIBS += -ldl
21+
else ifneq (, $(findstring mingw, $(SYS)))
22+
SUFFIX := dll
23+
LDFLAGS := -shared
24+
else
25+
$(error Unsupported build platform)
26+
endif
27+
28+
29+
30+
31+
ifndef GLOBALS_HOME
32+
$(error Couldn't find GLOBALS_HOME)
33+
endif
34+
35+
ifndef PYTHONHOME
36+
$(error Couldn't find PYTHONHOME)
37+
endif
38+
39+
PYTHONVER := $(shell ${PYTHONHOME}python -c "import sys; print(sys.version_info[0],sys.version_info[1],sep='')")
40+
LIBS = -lpython${PYTHONVER}
41+
42+
LDFLAGS += -L${PYTHONHOME}/Libs
43+
44+
INCLUDES += -I${GLOBALS_HOME}/dev/cpp/include
45+
INCLUDES += -I${PYTHONHOME}/include
46+
CFLAGS += $(INCLUDES)
47+
48+
.PHONY: all clean
49+
50+
all: iscpython.$(SUFFIX)
51+
52+
iscpython.o: iscpython.c
53+
54+
iscpython.$(SUFFIX): iscpython.o
55+
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
56+
57+
clean:
58+
$(RM) *.$(SUFFIX) *.o

c/iscpython.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
============================================================================
3+
Name : iscpython.c
4+
Author :
5+
Version :
6+
Copyright : MIT
7+
Description : Python callout library for InterSystems Platforms
8+
============================================================================
9+
*/
10+
11+
#define ZF_DLL /* Required only for dynamically linked libraries. */
12+
13+
#include <cdzf.h>
14+
#include <Python.h>
15+
16+
#undef ERROR
17+
/*
18+
*
19+
#include <stdio.h>
20+
#include <stdlib.h>
21+
*/
22+
23+
24+
// Reference to scope in which top-level code executes.
25+
PyObject *mainModule;
26+
27+
// Initializes Python environment
28+
// and obtains reference to the main module, to be used by
29+
int Initialize() {
30+
Py_Initialize();
31+
mainModule = PyImport_AddModule("__main__");
32+
return ZF_SUCCESS;
33+
}
34+
35+
int Finalize() {
36+
Py_DECREF(mainModule);
37+
Py_Finalize();
38+
return ZF_SUCCESS;
39+
}
40+
41+
42+
// Test method, returns random double
43+
int GetRandom(double* random) {
44+
45+
Py_Initialize();
46+
// https://stackoverflow.com/questions/3286448/calling-a-python-method-from-c-c-and-extracting-its-return-value
47+
// First, import your module :
48+
PyObject* myModuleString = PyUnicode_FromString((char*) "random");
49+
PyObject* myModule = PyImport_Import(myModuleString);
50+
51+
// Then getting a reference to your function :
52+
PyObject* myFunction = PyObject_GetAttrString(myModule, (char*) "random");
53+
//PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
54+
PyObject* args = PyTuple_Pack(0);
55+
56+
//Then getting your result :
57+
PyObject* myResult = PyObject_CallObject(myFunction, args);
58+
59+
//And getting back to a double :
60+
double result = PyFloat_AsDouble(myResult);
61+
62+
//Py_Main(argc, argv);
63+
Py_Finalize();
64+
*random = result;
65+
// set value to be returned by the $ZF function call
66+
return ZF_SUCCESS; // set the exit status code
67+
}
68+
69+
// Test method, returns random double
70+
int GetRandomSimple(double* random) {
71+
72+
Py_Initialize();
73+
PyRun_SimpleString("import random;");
74+
PyRun_SimpleString("x=random.random();");
75+
76+
PyObject *mainModule = PyImport_AddModule("__main__");
77+
PyObject *var = PyObject_GetAttrString(mainModule, "x");
78+
79+
*random = PyFloat_AsDouble(var);
80+
Py_Finalize();
81+
82+
return ZF_SUCCESS;
83+
}
84+
85+
// Does complete initialization, executes code and finalizes environment
86+
int SimpleStringFull(char *command, double* result) {
87+
88+
Py_Initialize();
89+
PyRun_SimpleString(command);
90+
91+
PyObject *mainModule = PyImport_AddModule("__main__");
92+
PyObject *var = PyObject_GetAttrString(mainModule, "x");
93+
94+
*result = PyFloat_AsDouble(var);
95+
Py_Finalize();
96+
97+
return ZF_SUCCESS;
98+
}
99+
100+
// Assumes initialized environment
101+
int SimpleString(char *command, char *resultVar, char* result) {
102+
PyRun_SimpleString(command);
103+
104+
int exists = PyObject_HasAttrString(mainModule, resultVar);
105+
106+
if (exists == 1) {
107+
PyObject *var = PyObject_GetAttrString(mainModule, resultVar);
108+
109+
//PyObject* varStr = PyObject_Repr(var);
110+
PyObject* varStr = PyObject_Str(var);
111+
char* str = PyUnicode_AsUTF8(varStr);
112+
113+
sprintf(result, "%s", str);
114+
115+
Py_DECREF(varStr);
116+
Py_DECREF(var);
117+
}
118+
119+
return ZF_SUCCESS;
120+
}
121+
122+
// Code for testing and debugging as an executable
123+
int main(int argc, char **argv) {
124+
printf("X: ");
125+
126+
//double random = 0;
127+
//GetRandom(&random);
128+
//GetRandomSimple(&random);
129+
//printf("%lf", random);
130+
131+
char* result = malloc(sizeof(char) * 1024);
132+
133+
Initialize();
134+
SimpleString("x=2", "y", result);
135+
Finalize();
136+
137+
printf(result);
138+
return EXIT_SUCCESS;
139+
}
140+
141+
ZFBEGIN
142+
ZFENTRY("Initialize","",Initialize)
143+
ZFENTRY("Finalize","",Finalize)
144+
ZFENTRY("GetRandom","D",GetRandom)
145+
ZFENTRY("GetRandomSimple","D",GetRandomSimple)
146+
ZFENTRY("SimpleStringFull","cD",SimpleStringFull)
147+
ZFENTRY("SimpleString","ccC",SimpleString)
148+
ZFEND

0 commit comments

Comments
 (0)