Skip to content

Commit a1da7bd

Browse files
committed
Save and Restore Python context from Interoperability adapter
1 parent 9e93b32 commit a1da7bd

File tree

7 files changed

+115
-15
lines changed

7 files changed

+115
-15
lines changed

isc/py/data/Context.cls

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Property History As list Of %VarString;
2020
/// Creation timestamp.
2121
Property CreatedOn As %TimeStamp [ InitialExpression = {$ZDATETIME($ZTIMESTAMP, 3, 1, 3)} ];
2222

23+
/// Alias of Pickle module, if any.
24+
Property %PickleAlias As %String [ InitialExpression = "pickle", Transient ];
25+
2326
/// Does not work
2427
/// See https://stackoverflow.com/questions/53959362/how-to-get-history-from-python-c-api
2528
Method PopulateHistory() As %Status
@@ -120,13 +123,14 @@ Method Restore(verbose As %Boolean = {$$$NO}, clear As %Boolean = {$$$NO}) As %S
120123
{
121124
do:clear ##class(isc.py.Callout).Finalize()
122125

126+
do ..InitPickle()
127+
123128
// Restoring modules
124129
for {
125130
set alias = ..Modules.GetNext(.module)
126131
quit:(module = "")
127132
do ##class(isc.py.Callout).SimpleString("import " _ module _ " as " _ alias)
128133
}
129-
130134

131135
// Restoring variables
132136
for i=1:1:..Variables.Count() {
@@ -141,6 +145,24 @@ Method Restore(verbose As %Boolean = {$$$NO}, clear As %Boolean = {$$$NO}) As %S
141145
quit $$$OK
142146
}
143147

148+
/// Calculate Pickle alias and import pickle if required
149+
Method InitPickle()
150+
{
151+
#dim importedPickle As %Boolean = $$$NO
152+
153+
for {
154+
set alias = ..Modules.GetNext(.module)
155+
quit:(module = "")
156+
157+
if (module="pickle") {
158+
set ..%PickleAlias = alias
159+
set importedPickle = $$$YES
160+
}
161+
}
162+
163+
do:'importedPickle ##class(isc.py.Callout).SimpleString("import pickle as " _ ..%PickleAlias)
164+
}
165+
144166
/// Wrapper for Display() method.
145167
/// id - either an id of a stored context or empty for current context
146168
/// do ##class(isc.py.data.Context).DisplayContext()

isc/py/data/Variable.cls

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ Method Display(indent As %String = "")
6868
write !
6969
}
7070

71-
/// Restore variable for disk.
71+
/// Restore variable from disk.
72+
/// context - variable owner Python context object.
7273
Method Restore(context As isc.py.data.Context)
7374
{
74-
do ##class(isc.py.Callout).SimpleString(..Name _ "=pickle.loads(" _ ..Pickle _ ")")
75+
do ##class(isc.py.Callout).SimpleString(..Name _ "=" _ context.%PickleAlias _ ".loads(" _ ..Pickle _ ")")
7576
}
7677

7778
Storage Default

isc/py/ens/Operation.cls

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,23 @@ Parameter ADAPTER = "isc.py.ens.OutboundAdapter";
66

77
Property Adapter As isc.py.ens.OutboundAdapter;
88

9-
/// This is the default message handler. All request types not declared in the message map are delivered here
10-
Method OnMessage(request As isc.py.ens.Request, Output response As isc.py.ens.Response) As %Status
9+
XData MessageMap
10+
{
11+
<MapItems>
12+
<MapItem MessageType="isc.py.msg.ExecutionRequest">
13+
<Method>Execute</Method>
14+
</MapItem>
15+
<MapItem MessageType="isc.py.msg.SaveRequest">
16+
<Method>SaveContext</Method>
17+
</MapItem>
18+
<MapItem MessageType="isc.py.msg.RestoreRequest">
19+
<Method>RestoreContext</Method>
20+
</MapItem>
21+
</MapItems>
22+
}
23+
24+
/// Execute arbitrary Python code
25+
Method Execute(request As isc.py.msg.ExecutionRequest, Output response As isc.py.msg.ExecutionResponse) As %Status
1126
{
1227
set response = ##class(isc.py.ens.Response).%New()
1328
set variables = $lfs(request.Variables)
@@ -35,5 +50,27 @@ Method OnMessage(request As isc.py.ens.Request, Output response As isc.py.ens.Re
3550
quit $$$OK
3651
}
3752

53+
/// Save context
54+
Method SaveContext(request As isc.py.msg.SaveRequest, Output response As Ens.StringResponse) As %Status
55+
{
56+
#dim sc As %Status = $$$OK
57+
#dim context As isc.py.data.Context
58+
set sc = ##class(isc.py.data.Context).SaveContext(.context)
59+
quit:$$$ISERR(sc) sc
60+
61+
set response = ##class(Ens.StringResponse).%New(context.%Id())
62+
63+
quit sc
64+
}
65+
66+
/// Restore context
67+
Method RestoreContext(request As isc.py.msg.RestoreRequest, Output response As Ens.Response) As %Status
68+
{
69+
#dim sc As %Status = $$$OK
70+
set sc = ##class(isc.py.data.Context).RestoreContext(request.ContextId)
71+
set response = ##class(Ens.Response).%New()
72+
quit sc
73+
}
74+
3875
}
3976

isc/py/ens/Request.cls renamed to isc/py/msg/ExecutionRequest.cls

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/// Request to python operation
2-
Class isc.py.ens.Request Extends Ens.Request
1+
/// Request to execute code for python operation
2+
Class isc.py.msg.ExecutionRequest Extends Ens.Request
33
{
44

55
/// Python code to execute
@@ -16,22 +16,19 @@ Property SeparateLines As %Boolean [ InitialExpression = {$$$YES} ];
1616

1717
Storage Default
1818
{
19-
<Data name="RequestDefaultData">
20-
<Subscript>"Request"</Subscript>
19+
<Data name="ExecutionRequestDefaultData">
20+
<Subscript>"ExecutionRequest"</Subscript>
2121
<Value name="1">
2222
<Value>Code</Value>
2323
</Value>
2424
<Value name="2">
2525
<Value>Variables</Value>
2626
</Value>
2727
<Value name="3">
28-
<Value>LineSeparator</Value>
29-
</Value>
30-
<Value name="4">
3128
<Value>SeparateLines</Value>
3229
</Value>
3330
</Data>
34-
<DefaultData>RequestDefaultData</DefaultData>
31+
<DefaultData>ExecutionRequestDefaultData</DefaultData>
3532
<Type>%Library.CacheStorage</Type>
3633
}
3734

isc/py/ens/Response.cls renamed to isc/py/msg/ExecutionResponse.cls

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// Response from Python environment
2-
Class isc.py.ens.Response Extends Ens.Response
2+
Class isc.py.msg.ExecutionResponse Extends Ens.Response
33
{
44

55
/// Array of Python variables
@@ -10,7 +10,7 @@ Storage Default
1010
<Data name="Variables">
1111
<Attribute>Variables</Attribute>
1212
<Structure>subnode</Structure>
13-
<Subscript>"isc.py.ens.Response.Variables"</Subscript>
13+
<Subscript>"isc.py.msg.ExecutionResponse.Variables"</Subscript>
1414
</Data>
1515
<Type>%Library.CacheStorage</Type>
1616
}

isc/py/msg/RestoreRequest.cls

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// Restore saved Python context
2+
Class isc.py.msg.RestoreRequest Extends Ens.Request
3+
{
4+
5+
/// Context identifier to restore
6+
Property ContextId As %Integer;
7+
8+
Storage Default
9+
{
10+
<Data name="RestoreRequestDefaultData">
11+
<Subscript>"RestoreRequest"</Subscript>
12+
<Value name="1">
13+
<Value>ContextId</Value>
14+
</Value>
15+
</Data>
16+
<DefaultData>RestoreRequestDefaultData</DefaultData>
17+
<Type>%Library.CacheStorage</Type>
18+
}
19+
20+
}
21+

isc/py/msg/SaveRequest.cls

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// Save Python context to disk.
2+
Class isc.py.msg.SaveRequest Extends Ens.Request
3+
{
4+
5+
/// TODO Only variables that satisfy Mask are saved.
6+
/// Wildcards * and ? are accepted, masks are commaseparated.
7+
Property Mask As %VarString [ InitialExpression = "*" ];
8+
9+
Storage Default
10+
{
11+
<Data name="SaveRequestDefaultData">
12+
<Subscript>"SaveRequest"</Subscript>
13+
<Value name="1">
14+
<Value>Mask</Value>
15+
</Value>
16+
</Data>
17+
<DefaultData>SaveRequestDefaultData</DefaultData>
18+
<Type>%Library.CacheStorage</Type>
19+
}
20+
21+
}
22+

0 commit comments

Comments
 (0)