Skip to content

Commit cebbcd4

Browse files
committed
Stream requests / responses for Interoperability
Fixed #23
1 parent 9de6fb5 commit cebbcd4

File tree

6 files changed

+134
-1
lines changed

6 files changed

+134
-1
lines changed

isc/py/Callout.cls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// Raw callout wrapper. Use isc.py.Main
22
/// To use:
33
/// 1. Call: do ##class(isc.py.Callout).Setup() once per systems start
4-
/// 2. Call main method (can be called many times, context persists): write ##class(isc.py.Callout).SimpleString(code, data)
4+
/// 2. Call main method (can be called many times, context persists): write ##class(isc.py.Callout).SimpleString(code, variable)
55
/// 3. Call: do ##class(isc.py.Callout).Finalize() to clear Python context
66
/// 4. Call: write ##class(isc.py.Callout).Unload() to free callout library
77
Class isc.py.Callout

isc/py/ens/Operation.cls

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Property Adapter As isc.py.ens.OutboundAdapter;
99
XData MessageMap
1010
{
1111
<MapItems>
12+
<MapItem MessageType="isc.py.msg.StreamExecutionRequest">
13+
<Method>StreamExecute</Method>
14+
</MapItem>
1215
<MapItem MessageType="isc.py.msg.ExecutionRequest">
1316
<Method>Execute</Method>
1417
</MapItem>
@@ -52,6 +55,28 @@ Method Execute(request As isc.py.msg.ExecutionRequest, Output response As isc.py
5255
quit sc
5356
}
5457

58+
/// Execute arbitrary Python code
59+
Method StreamExecute(request As isc.py.msg.StreamExecutionRequest, Output response As isc.py.msg.StreamExecutionResponse) As %Status
60+
{
61+
#dim sc As %Status = $$$OK
62+
set response = ##class(isc.py.msg.StreamExecutionResponse).%New()
63+
set variables = $lfs(request.Variables)
64+
65+
set sc = ..Adapter.StreamExecute(request.Code, request.SeparateLines)
66+
quit:$$$ISERR(sc) sc
67+
68+
for i=1:1:$ll(variables) {
69+
set variable = $lg(variables, i)
70+
continue:variable=""
71+
kill stream
72+
set sc = ##class(isc.py.Main).GetVariable(variable, ##class(isc.py.Callout).#SerializationStr, .stream)
73+
do response.Variables.SetAt(stream, variable)
74+
quit:$$$ISERR(sc)
75+
}
76+
77+
quit sc
78+
}
79+
5580
/// Save context
5681
Method SaveContext(request As isc.py.msg.SaveRequest, Output response As Ens.StringResponse) As %Status
5782
{

isc/py/ens/OutboundAdapter.cls

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,29 @@ Method Execute(code = "", variable = "", lineSeparator As %String = {$c(10)}, Ou
5454
quit $g(result)
5555
}
5656

57+
/// Main method execute stream
58+
/// All arguments are optional.
59+
/// code - Python code to execute
60+
/// lineSeparator - separate code into lines. Defaults to $c(10).
61+
Method StreamExecute(code As %Stream.GlobalCharacter, separateLines As %Boolean = {$$$YES}) As %Status
62+
{
63+
#dim sc As %Status = $$$OK
64+
65+
if separateLines = $$$YES {
66+
set code.LineTerminator = $c(10)
67+
68+
while 'code.AtEnd {
69+
set line = code.ReadLine($$$MaxLocalLength)
70+
$$$TRACE("Var: " _ line)
71+
set sc = ##class(isc.py.Main).SimpleString(line)
72+
quit:$$$ISERR(sc)
73+
}
74+
} else {
75+
set sc = ##class(isc.py.Main).ExcuteCode(code)
76+
}
77+
78+
quit sc
79+
}
80+
5781
}
5882

isc/py/msg/StreamExecutionRequest.cls

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// Same as ExecutionRequest but Code is a stream
2+
Class isc.py.msg.StreamExecutionRequest Extends Ens.Request
3+
{
4+
5+
/// Python code to execute
6+
Property Code As %Stream.GlobalCharacter;
7+
8+
/// Comma-separated list of variables to get in response message
9+
Property Variables As %String;
10+
11+
/// Separate incoming message into lines for execution.
12+
/// $c(10) is used for line separation
13+
/// Note that it's NOT recommended to process whole message at once,
14+
/// this feature is only for `def` and similar multi-line expressions processing.
15+
Property SeparateLines As %Boolean [ InitialExpression = {$$$YES} ];
16+
17+
Storage Default
18+
{
19+
<Data name="StreamExecutionRequestDefaultData">
20+
<Subscript>"StreamExecutionRequest"</Subscript>
21+
<Value name="1">
22+
<Value>Code</Value>
23+
</Value>
24+
<Value name="2">
25+
<Value>Variables</Value>
26+
</Value>
27+
<Value name="3">
28+
<Value>SeparateLines</Value>
29+
</Value>
30+
</Data>
31+
<DefaultData>StreamExecutionRequestDefaultData</DefaultData>
32+
<Type>%Library.CacheStorage</Type>
33+
}
34+
35+
}
36+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// Response from Python environment
2+
Class isc.py.msg.StreamExecutionResponse Extends Ens.Response
3+
{
4+
5+
/// Array of Python variables
6+
Property Variables As array Of %Stream.GlobalCharacter(XMLPROJECTION = "NONE");
7+
8+
Storage Default
9+
{
10+
<Data name="Variables">
11+
<Attribute>Variables</Attribute>
12+
<Structure>subnode</Structure>
13+
<Subscript>"isc.py.msg.StreamExecutionResponse.Variables"</Subscript>
14+
</Data>
15+
<Type>%Library.CacheStorage</Type>
16+
}
17+
18+
}
19+

isc/py/unit/TestCase.cls

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,5 +173,34 @@ Method TestMultiline()
173173
do ##class(isc.py.Callout).SimpleString("del cube")
174174
}
175175

176+
/// do ##class(isc.py.unit.TestCase).TestProductionStream()
177+
ClassMethod TestProductionStream(count As %Integer = 1000000, separateLines As %Boolean = {$$$YES})
178+
{
179+
set variable = "x"
180+
set stream = ##class(%Stream.GlobalCharacter).%New()
181+
for i=1:1:count {
182+
do stream.WriteLine((variable _ "=" _ i))
183+
}
184+
do stream.%Save()
185+
186+
write "Count: ", count, !
187+
write "SeparateLines: ", separateLines, !
188+
write "Size: ", stream.Size, !
189+
190+
set request = ##class(isc.py.msg.StreamExecutionRequest).%New()
191+
set request.Code = stream
192+
set request.Variables = variable
193+
set request.SeparateLines = $$$YES
194+
195+
#dim response As isc.py.msg.StreamExecutionResponse
196+
set sc = ##class(EnsLib.Testing.Service).SendTestRequest("isc.py.ens.Operation", request, .response, .sessionId, $$$YES)
197+
198+
set:$$$ISOK(sc) value = response.Variables.GetAt(variable).Read()
199+
200+
write "Status: ", $select($$$ISOK(sc):sc, 1:$System.Status.GetErrorText(sc)), !
201+
write "Value: ", $g(value), !
202+
write "SessionId: ", $g(sessionId), !
203+
}
204+
176205
}
177206

0 commit comments

Comments
 (0)