Skip to content

Commit 0f87efd

Browse files
committed
Add methods to work with streams to Callout library
1 parent 0c16490 commit 0f87efd

File tree

2 files changed

+126
-16
lines changed

2 files changed

+126
-16
lines changed

c/iscpython.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ PyObject *mainModule;
3232
// Relevant for SimpleString method
3333
bool isInitialized = false;
3434

35+
// Pointer to incoming code to execute
36+
char* inStream = NULL;
37+
38+
// Current position in incoming code to execute
39+
int curpos = 0;
40+
41+
// Size of inStream pointer
42+
int maxpos = 0;
43+
3544
// Initializes Python environment
3645
// and obtains reference to the main module, to be used by
3746
int Initialize() {
@@ -158,6 +167,57 @@ int SimpleString(CACHE_EXSTRP command, char *resultVar, int serialization, CACHE
158167
return ZF_SUCCESS;
159168
}
160169

170+
// Init incoming stream (inStream) to length bytes + 1
171+
int StreamInit(int length)
172+
{
173+
if (!inStream) {
174+
free(inStream);
175+
inStream = NULL;
176+
}
177+
inStream = malloc(1 + sizeof(char) * length);
178+
curpos = 0;
179+
maxpos = length;
180+
181+
if (!inStream) {
182+
return ZF_FAILURE;
183+
}
184+
185+
return ZF_SUCCESS;
186+
}
187+
188+
// Write piece of inStream
189+
int StreamWrite(CACHE_EXSTRP command)
190+
{
191+
if ((!inStream) || (command->len + curpos > maxpos)) {
192+
return ZF_FAILURE;
193+
}
194+
195+
memcpy(inStream + curpos, command->str.ch, command->len);
196+
curpos += command->len;
197+
return ZF_SUCCESS;
198+
}
199+
200+
// Send inStream to Python and free it
201+
int StreamExecute()
202+
{
203+
if (isInitialized == false) {
204+
Initialize();
205+
}
206+
207+
if (!inStream) {
208+
return ZF_FAILURE;
209+
}
210+
211+
memcpy(inStream + curpos, "\0", 1);
212+
213+
PyRun_SimpleString(inStream);
214+
free(inStream);
215+
inStream = NULL;
216+
curpos = 0;
217+
218+
return ZF_SUCCESS;
219+
}
220+
161221
// Code for testing and debugging as an executable
162222
int main(int argc, char **argv) {
163223
printf("X: ");
@@ -184,4 +244,7 @@ ZFBEGIN
184244
ZFENTRY("GetRandomSimple","D",GetRandomSimple)
185245
ZFENTRY("SimpleStringFull","cD",SimpleStringFull)
186246
ZFENTRY("SimpleString","jciJ",SimpleString)
247+
ZFENTRY("StreamInit","i",StreamInit)
248+
ZFENTRY("StreamWrite","j",StreamWrite)
249+
ZFENTRY("StreamExecute","",StreamExecute)
187250
ZFEND

isc/py/Callout.cls

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ Parameter SimpleStringFull As Integer = 5;
2121

2222
Parameter SimpleString As Integer = 6;
2323

24+
Parameter StreamInit As Integer = 7;
25+
26+
Parameter StreamWrite As Integer = 8;
27+
28+
Parameter StreamExecute As Integer = 9;
29+
2430
/// Get path to the shared library file.
2531
/// Library file is assumed to be in a bin folder, unless specified otherwise in ^isc.py.Callout global.
2632
/// write ##class(isc.py.Callout).GetLib()
@@ -95,6 +101,63 @@ ClassMethod SimpleString(code As %String = "", variable As %String = "", seriali
95101
quit result
96102
}
97103

104+
/// Init incoming Stream
105+
/// write ##class(isc.py.Callout).StreamInit()
106+
ClassMethod StreamInit(length As %Integer) As %Status
107+
{
108+
#dim sc As %Status = $$$OK
109+
try {
110+
do $ZF(-6, ..#PyLibId, ..#StreamInit, length)
111+
} catch ex {
112+
#dim ex As %Exception.General
113+
if (ex.Name = "<FUNCTION>") {
114+
set sc = $$$ERROR($$$GeneralError, "Unable to allocate memory")
115+
} else {
116+
set sc = ex.AsStatus()
117+
}
118+
}
119+
120+
quit sc
121+
}
122+
123+
/// Write piece into incoming Stream
124+
/// write ##class(isc.py.Callout).StreamWrite()
125+
ClassMethod StreamWrite(code As %String = "") As %Status
126+
{
127+
#dim sc As %Status = $$$OK
128+
try {
129+
do $ZF(-6, ..#PyLibId, ..#StreamWrite, code)
130+
} catch ex {
131+
#dim ex As %Exception.General
132+
if (ex.Name = "<FUNCTION>") {
133+
set sc = $$$ERROR($$$GeneralError, "Call StreamInit before calling StreamWrite. Or attempted to write into stream more than allocated data.")
134+
} else {
135+
set sc = ex.AsStatus()
136+
}
137+
}
138+
139+
quit sc
140+
}
141+
142+
/// Send incoming stream to Python for execution and free it.
143+
/// write ##class(isc.py.Callout).StreamExecute()
144+
ClassMethod StreamExecute() As %Status
145+
{
146+
#dim sc As %Status = $$$OK
147+
try {
148+
do $ZF(-6, ..#PyLibId, ..#StreamExecute)
149+
} catch ex {
150+
#dim ex As %Exception.General
151+
if (ex.Name = "<FUNCTION>") {
152+
set sc = $$$ERROR($$$GeneralError, "Call StreamInit and StreamWrite before calling StreamExecute")
153+
} else {
154+
set sc = ex.AsStatus()
155+
}
156+
}
157+
158+
quit sc
159+
}
160+
98161
/// Finalize Python. Idempotent.
99162
/// do ##class(isc.py.Callout).Finalize()
100163
ClassMethod Finalize() As %Integer
@@ -110,21 +173,5 @@ ClassMethod Unload() As %Integer
110173
quit result
111174
}
112175

113-
/// Returns last occured exception in Python and clears it
114-
/// write ##class(isc.py.Callout).GetStatus()
115-
ClassMethod GetStatus() As %Status
116-
{
117-
do ##class(isc.py.Callout).SimpleString("import sys, traceback")
118-
set haxExc = ##class(isc.py.Callout).SimpleString("zzzerr = hasattr(sys, 'last_type')", "zzzerr")
119-
120-
quit:haxExc="False" $$$OK
121-
122-
set excText = ##class(isc.py.Callout).SimpleString("zzzerr = traceback.format_exception(sys.last_type, sys.last_value, sys.last_traceback)", "zzzerr")
123-
set excText = $zcvt($zcvt(excText, "I", "UTF8"), "I", "JSON")
124-
do ##class(isc.py.Callout).SimpleString("del zzzerr, sys.last_type, sys.last_value, sys.last_traceback")
125-
126-
quit $$$ERROR($$$GeneralError, excText)
127-
}
128-
129176
}
130177

0 commit comments

Comments
 (0)