Skip to content

Commit b74b6a2

Browse files
committed
Context persistence
1 parent 844b45e commit b74b6a2

File tree

2 files changed

+307
-0
lines changed

2 files changed

+307
-0
lines changed

isc/py/data/Context.cls

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/// Python context
2+
Class isc.py.data.Context Extends %Persistent
3+
{
4+
5+
/// Short name.
6+
Property Name As %String;
7+
8+
/// Extended info.
9+
Property Description As %VarString;
10+
11+
/// List of variables.
12+
Property Variables As list Of isc.py.data.Varable;
13+
14+
/// Array or loaded modules, key - module name, value - alias.
15+
Property Modules As array Of %String(SQLPROJECTION = "table/column", STORAGEDEFAULT = "array");
16+
17+
/// History of executed commands. Currently does not work.
18+
Property History As list Of %VarString;
19+
20+
/// Creation timestamp.
21+
Property CreatedOn As %TimeStamp [ InitialExpression = {$ZDATETIME($ZTIMESTAMP, 3, 1, 3)} ];
22+
23+
/// Does not work
24+
/// See https://stackoverflow.com/questions/53959362/how-to-get-history-from-python-c-api
25+
Method PopulateHistory() As %Status
26+
{
27+
#dim sc As %Status = $$$OK
28+
29+
set count = ##class(isc.py.Callout).SimpleString("zzzcount=readline.get_current_history_length()", "zzzcount")
30+
do ##class(isc.py.Callout).SimpleString("del zzzcount")
31+
zw count
32+
for i=1:1:count {
33+
set item = ##class(isc.py.Callout).SimpleString("zzzitem=readline.get_history_item("_i_")", "zzzitem")
34+
zw item
35+
}
36+
do ##class(isc.py.Callout).SimpleString("del zzzitem")
37+
38+
quit sc
39+
}
40+
41+
/// Get modules and their aliases
42+
Method PopulateModules() As %Status
43+
{
44+
set modules = ##class(isc.py.Callout).SimpleString("zzzmodules=json.dumps(list(zzzmodulesfunc()))", "zzzmodules")
45+
do ##class(isc.py.Callout).SimpleString("del zzzmodules")
46+
47+
set modules = {}.%FromJSON(modules)
48+
set iterator = modules.%GetIterator()
49+
while iterator.%GetNext(.key, .value) {
50+
set module = value.%Get(0)
51+
set alias = value.%Get(1)
52+
continue:module="builtins"
53+
do ..Modules.SetAt(alias, module)
54+
}
55+
}
56+
57+
/// Get variables and their values.
58+
Method PopulateVariables() As %Status
59+
{
60+
#dim sc As %Status = $$$OK
61+
62+
set variables = ##class(isc.py.Callout).SimpleString("zzzvars=json.dumps(list(zzzvarsfunc()))", "zzzvars")
63+
do ##class(isc.py.Callout).SimpleString("del zzzvars")
64+
65+
set variables = {}.%FromJSON(variables)
66+
set iterator = variables.%GetIterator()
67+
while iterator.%GetNext(.key, .variable) {
68+
#dim varObj As isc.py.data.Varable
69+
set sc = ##class(isc.py.data.Varable).SaveVariable(variable, .varObj)
70+
quit:$$$ISERR(sc)
71+
do ..Variables.Insert(varObj)
72+
}
73+
74+
quit sc
75+
}
76+
77+
/// Define basic methods.
78+
/// ToDo move to %OnNew?
79+
Method Init()
80+
{
81+
do ##class(isc.py.Callout).SimpleString("import types, json;") // readline
82+
do ##class(isc.py.Callout).SimpleString("def zzzmodulesfunc():"_ $c(10) _
83+
" for name, val in globals().items():"_ $c(10) _
84+
" if isinstance(val, types.ModuleType):"_ $c(10) _
85+
" yield val.__name__, name")
86+
do ##class(isc.py.Callout).SimpleString("def zzzvarsfunc():"_ $c(10) _
87+
" for name, val in globals().items():"_ $c(10) _
88+
" if not (isinstance(val, types.ModuleType) or name.startswith('_') or hasattr(val, '__call__')):"_ $c(10) _
89+
" yield name")
90+
}
91+
92+
/// Save Python context on disk
93+
/// set sc=##class(isc.py.data.Context).SaveContext()
94+
ClassMethod SaveContext(verose As %Boolean = {$$$NO}, Output context As isc.py.data.Context) As %Status
95+
{
96+
set context = ..%New()
97+
do context.Init()
98+
//do obj.PopulateHistory()
99+
do context.PopulateModules()
100+
do context.PopulateVariables()
101+
do:verose context.Display()
102+
103+
quit context.%Save()
104+
}
105+
106+
/// Restore context. Load modules and variables.
107+
/// do ##class(isc.py.data.Context).RestoreContext()
108+
ClassMethod RestoreContext(id As %Integer, verbose As %Boolean = {$$$NO}, clear As %Boolean = {$$$NO}) As %Status
109+
{
110+
set context = ..%OpenId(id,,.sc)
111+
quit:$$$ISERR(sc) sc
112+
quit context.Restore(verbose, clear)
113+
}
114+
115+
/// Internal restore method.
116+
/// verbose - dispplay info about restored context.
117+
/// clear - destroy environment before populating the context.
118+
Method Restore(verbose As %Boolean = {$$$NO}, clear As %Boolean = {$$$NO}) As %Status
119+
{
120+
do:clear ##class(isc.py.Callout).Finalize()
121+
122+
// Restoring modules
123+
for {
124+
set alias = ..Modules.GetNext(.module)
125+
quit:(module = "")
126+
do ##class(isc.py.Callout).SimpleString("import " _ module _ " as " _ alias)
127+
}
128+
129+
130+
// Restoring variables
131+
for i=1:1:..Variables.Count() {
132+
set variable = ..Variables.GetAt(i)
133+
do variable.Restore()
134+
}
135+
136+
do:verbose ..Display()
137+
138+
quit $$$OK
139+
}
140+
141+
/// Wrapper for Display() method.
142+
/// id - either an id of a stored context or empty for current context
143+
/// do ##class(isc.py.data.Context).DisplayContext()
144+
ClassMethod DisplayContext(id As %Integer = "")
145+
{
146+
if id'="" {
147+
set context = ..%OpenId(id,,.sc)
148+
quit:$$$ISERR(sc) sc
149+
} else {
150+
set context = ..%New()
151+
do context.Init()
152+
do context.PopulateModules()
153+
do context.PopulateVariables()
154+
}
155+
156+
do context.Display()
157+
}
158+
159+
/// Display context
160+
Method Display()
161+
{
162+
set indent = " "
163+
write "Name: " _ ..Name, !
164+
write "Description: " _ ..Description, !
165+
write "CreatedOn: " _ ..CreatedOn, !
166+
write "Modules:", !
167+
168+
for {
169+
set alias = ..Modules.GetNext(.module)
170+
quit:(module = "")
171+
write indent, module, " as ", alias, !
172+
}
173+
174+
write "Variables:", !
175+
for i=1:1:..Variables.Count() {
176+
set variable = ..Variables.GetAt(i)
177+
do variable.Display(indent)
178+
}
179+
}
180+
181+
Storage Default
182+
{
183+
<Data name="ContextDefaultData">
184+
<Value name="1">
185+
<Value>%%CLASSNAME</Value>
186+
</Value>
187+
<Value name="2">
188+
<Value>Name</Value>
189+
</Value>
190+
<Value name="3">
191+
<Value>Description</Value>
192+
</Value>
193+
<Value name="4">
194+
<Value>Variables</Value>
195+
</Value>
196+
<Value name="5">
197+
<Value>History</Value>
198+
</Value>
199+
<Value name="6">
200+
<Value>CreatedOn</Value>
201+
</Value>
202+
</Data>
203+
<Data name="Modules">
204+
<Attribute>Modules</Attribute>
205+
<Structure>subnode</Structure>
206+
<Subscript>"Modules"</Subscript>
207+
</Data>
208+
<DataLocation>^isc.py.data.ContextD</DataLocation>
209+
<DefaultData>ContextDefaultData</DefaultData>
210+
<IdLocation>^isc.py.data.ContextD</IdLocation>
211+
<IndexLocation>^isc.py.data.ContextI</IndexLocation>
212+
<StreamLocation>^isc.py.data.ContextS</StreamLocation>
213+
<Type>%Library.CacheStorage</Type>
214+
}
215+
216+
}
217+

isc/py/data/Varable.cls

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/// Stored Python variable
2+
Class isc.py.data.Varable Extends %Persistent
3+
{
4+
5+
/// Variable Name
6+
Property Name As %String;
7+
8+
/// Variable Class
9+
Property Type As %String;
10+
11+
/// Variable repr
12+
Property Value As %VarString;
13+
14+
/// Variable JSON serialization
15+
Property JSON As %VarString;
16+
17+
/// Save variable on disk.
18+
/// zw ##class(isc.py.data.Varable).SaveVariable()
19+
ClassMethod SaveVariable(name As %String = "", Output variable As isc.py.data.Varable) As %Status
20+
{
21+
kill var
22+
quit:name="" $$$ERROR($$$GeneralError, "Variable name can't be empty")
23+
24+
set repr = ##class(isc.py.Callout).SimpleString(,name, 1)
25+
quit:repr="" $$$ERROR($$$GeneralError, $$$FormatText("Variable %1 is empty or initialized", name))
26+
27+
set type = ##class(isc.py.Callout).SimpleString("zzztype=type("_name_").__name__", "zzztype")
28+
do ##class(isc.py.Callout).SimpleString("import json;")
29+
set json = ##class(isc.py.Callout).SimpleString("zzzjson=json.dumps(r)", "zzzjson")
30+
do ##class(isc.py.Callout).SimpleString("del zzztype, zzzjson")
31+
32+
set variable = ..%New()
33+
set variable.Name = name
34+
set variable.Value = repr
35+
set variable.Type = type
36+
set variable.JSON = json
37+
set sc = variable.%Save()
38+
39+
quit sc
40+
}
41+
42+
/// Dispaly variable on the current device.
43+
Method Display(indent As %String = "")
44+
{
45+
write indent, "Name: ", ..Name, !
46+
write indent, "Type: ", ..Type, !
47+
set limit = 100
48+
If $l(..Value)<=limit {
49+
Write indent, "Value: ", ..Value, !
50+
} Else {
51+
Write indent, "Value (truncated): ", $e(..Value,1,limit), !
52+
}
53+
write !
54+
}
55+
56+
/// Restore variable for disk.
57+
Method Restore()
58+
{
59+
do ##class(isc.py.Callout).SimpleString(..Name _ "=" _ ..Value)
60+
}
61+
62+
Storage Default
63+
{
64+
<Data name="VarableDefaultData">
65+
<Value name="1">
66+
<Value>%%CLASSNAME</Value>
67+
</Value>
68+
<Value name="2">
69+
<Value>Name</Value>
70+
</Value>
71+
<Value name="3">
72+
<Value>Type</Value>
73+
</Value>
74+
<Value name="4">
75+
<Value>Value</Value>
76+
</Value>
77+
<Value name="5">
78+
<Value>JSON</Value>
79+
</Value>
80+
</Data>
81+
<DataLocation>^isc.py.data.VarableD</DataLocation>
82+
<DefaultData>VarableDefaultData</DefaultData>
83+
<IdLocation>^isc.py.data.VarableD</IdLocation>
84+
<IndexLocation>^isc.py.data.VarableI</IndexLocation>
85+
<StreamLocation>^isc.py.data.VarableS</StreamLocation>
86+
<Type>%Library.CacheStorage</Type>
87+
}
88+
89+
}
90+

0 commit comments

Comments
 (0)