Skip to content

Commit 35561a0

Browse files
committed
pre-alex-fixes
1 parent 414e8ec commit 35561a0

13 files changed

+492
-66
lines changed

.devcontainer/devcontainer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// We define and use a `server` so that (a) a user-level `objectscript.conn.server` properly doesn't override us, and (b) so InterSystems
1818
// Server Manager can also be used.
1919
"settings": {
20-
"objectscript.conn" :{
20+
"objectscript.conn": {
2121
"server": "devcontainer",
2222
"active": true,
2323
},

.vscode/settings copy.json

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"files.associations": {
3+
4+
"Dockerfile*": "dockerfile",
5+
"iris.script": "objectscript"
6+
},
7+
"objectscript.conn" :{
8+
"ns": "USER",
9+
"username": "_SYSTEM",
10+
"password": "SYS",
11+
"docker-compose": {
12+
"service": "iris",
13+
"internalPort": 52773
14+
},
15+
"active": false
16+
},
17+
"sqltools.connections": [
18+
{
19+
"namespace": "USER",
20+
"connectionMethod": "Server and Port",
21+
"showSystem": false,
22+
"previewLimit": 50,
23+
"server": "localhost",
24+
"port": 32770,
25+
"askForPassword": false,
26+
"driver": "InterSystems IRIS",
27+
"name": "objectscript-docker",
28+
"username": "_SYSTEM",
29+
"password": "SYS"
30+
}
31+
]
32+
33+
}

.vscode/settings.json

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
{
22
"files.associations": {
3-
43
"Dockerfile*": "dockerfile",
54
"iris.script": "objectscript"
65
},
76
"objectscript.conn" :{
87
"ns": "USER",
9-
"username": "_SYSTEM",
10-
"password": "SYS",
11-
"docker-compose": {
12-
"service": "iris",
13-
"internalPort": 52773
14-
},
8+
"username": "rsingh",
9+
"server": "iris-local",
1510
"active": true
1611
},
1712
"sqltools.connections": [

docker-compose.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ services:
77
restart: always
88
command: --check-caps false
99
ports:
10-
- 1972
11-
- 52773
12-
- 53773
10+
- 1979:1972
11+
- 52779:52773
12+
- 53779:53773
1313
volumes:
1414
- ./:/irisrun/repo

src/Py/Helper.cls

+264
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/// <pre>
2+
/// Author - Alex Woodhead 2021-04-26 - V1 IRIS arrays and Lists to Py Dict and List<br/>
3+
/// 2021-05-07 - Added support for py Dict and List back to IRIS array and List<br/>
4+
/// Added Error log notifications for unsupported types.
5+
/// Added string only keys for dictionaries
6+
/// </pre>
7+
///
8+
/// Mission:<br/>
9+
/// A convenience utility to convert between:<ul>
10+
/// <li>IRIS LIST and Python list</li>
11+
/// <li>IRIS array and Python dictionary</li>
12+
///
13+
/// Method:<br/>
14+
/// When converting IRIS arrays to Python dictionaries
15+
/// the keys generated (for key,values) will always be strings.<br/>
16+
/// This simplifies implementation IRIS->Python by providing consist output
17+
/// whatever the invocation style is in IRIS.
18+
/// <br/>
19+
/// Conversion error information will be written to the IRIS event log<br/>
20+
/// </br>
21+
/// Whats is supported in both directions:<ul>
22+
/// <li>Converting IRIS Arrays to Py Dictionaries</li>
23+
/// <li>Converting IRIS multidimensional array to inner Py Dictionaries within Py Dictionaries</li>
24+
/// <li>Converting IRIS Arrays that also contain lists to Dictionaries with values of Py Lists</li>
25+
/// <li>Converting IRIS LIST to Py List</li>
26+
/// </ul>
27+
/// What is not supported:<ul>
28+
/// <li>Converting Py Lists that contain Py Dictionaries into IRIS LISTS</li>
29+
/// </ul>
30+
Class Py.Helper [ Abstract ]
31+
{
32+
33+
/// Allows dictionary key to be set
34+
/// python language provides "[]" mutator
35+
/// This method wraps this with a "Set" method
36+
/// <example>
37+
/// set impBi=##class(%SYS.Python).Import("builtins")
38+
/// set pRequest=impBi.dict()
39+
/// do ##class(Py.Helper).pyDictSet(pRequest,"Fname","Bob")
40+
/// do ##class(Py.Helper).pyDictSet(pRequest,"Mname","Henry")
41+
/// do ##class(Py.Helper).pyDictSet(pRequest,"Lname","Smith")
42+
/// zw pRequest
43+
/// pRequest=52@%SYS.Python ; {'Fname': 'Bob', 'Mname': 'Henry', 'Lname': 'Smith'} ; <OREF>
44+
/// </example>
45+
ClassMethod pyDictSet(ByRef dict As %SYS.Python, key, value)
46+
{
47+
// Force key names to strings
48+
do ..pyDictSetInner(dict,""_key_"",value)
49+
}
50+
51+
ClassMethod pyDictSetInner(ByRef dict As %SYS.Python, key, value) [ Language = python, Private ]
52+
{
53+
dict[key]=value
54+
}
55+
56+
/// Allows dictionary key to be removed
57+
/// python language provides del keyword
58+
/// This method wraps this with a "Kill" method
59+
/// <example>
60+
/// ; see pyDictSet method example for previous variable setup)
61+
/// zw pRequest
62+
/// pRequest=52@%SYS.Python ; {'Fname': 'Bob', 'Mname': 'Henry', 'Lname': 'Smith'} ; <OREF>
63+
/// do ##class(Py.Helper).pyDictKill(pRequest,"Mname")
64+
/// zw pRequest
65+
/// pRequest=52@%SYS.Python ; {'Fname': 'Bob', 'Lname': 'Smith'} ; <OREF>
66+
/// </example>
67+
ClassMethod pyDictKill(ByRef dict As %SYS.Python, key)
68+
{
69+
// Force key names to strings
70+
do ..pyDictKillInner(dict,""_key_"")
71+
}
72+
73+
ClassMethod pyDictKillInner(ByRef dict As %SYS.Python, key) [ Language = python, Private ]
74+
{
75+
del dict[key]
76+
}
77+
78+
/// Convert IRIS array variable to python dictionary
79+
/// Supports Nexted List Nodes as node values where IRIS Lists are converted to python Lists.
80+
/// Where there is a node value AND sub-nodes the node value is given dictionary key "_value"
81+
/// <example>
82+
/// set array=123
83+
/// set array(1)=456
84+
/// set array("ADDRESS",1,"ADD1")="HouseOrFlatNumber"
85+
/// set array("ADDRESS",1,"ADD2")="TownOrCity"
86+
/// set array("ADDRESS",1,"ADD3")="CountyOrRegion"
87+
/// set array("ADDRESS",1,"ADD4")="Country"
88+
/// set array("ADDRESS",1,"ADD5")="ZIPCode"
89+
/// set array("FNAME")="BOB"
90+
/// set array("LNAME")="SMITH"
91+
/// set array("ListTest",1)=$lb(1,2,$lb(3,4,"Five"))
92+
/// set myPyDict=##class(Py.Helper).pyDictFromArray(.array)
93+
/// zw myPyDict
94+
/// myPyDict=46@%SYS.Python ; {'_value': 123, '1': 456, 'ADDRESS': {1: {'ADD1': 'HouseOrFlatNumber', 'ADD2': 'TownOrCity', 'ADD3': 'CountyOrRegion', 'ADD4': 'Country', 'ADD5': 'ZIPCode'}}, 'FNAME': 'BOB', 'LNAME': 'SMITH', 'ListTest': {1: [1, 2, [3, 4, 'Five']]}} ; <OREF>
95+
/// </example>
96+
ClassMethod pyDictFromArray(ByRef array, ByRef ret As %SYS.Python = {$$$NULLOREF}, ByRef impBi As %SYS.Python = {##class(%SYS.Python).Import("builtins")}) As %SYS.Python [ ProcedureBlock = 1 ]
97+
{
98+
if ret=$$$NULLOREF {
99+
set ret=impBi.dict()
100+
if $Data(array)#2 {
101+
do ..pyDictSet(ret,"_value",..toPyListOrString(array,,impBi)) // Value of top node only
102+
}
103+
}
104+
set k1=""
105+
for {
106+
set k1=$O(array(k1),+1,data)
107+
quit:k1=""
108+
if $D(array(k1))=1 {
109+
do ..pyDictSet(ret,k1,..toPyListOrString(data,,impBi))
110+
continue
111+
}
112+
set k1dict=impBi.dict()
113+
do ..pyDictSet(ret,k1,k1dict) // pre-append dictionary to Key
114+
if $D(array(k1))=11 {
115+
do ..pyDictSet(k1dict,"_value",..toPyListOrString(data,,impBi))
116+
}
117+
kill subarry
118+
merge subarry=array(k1)
119+
do ..pyDictFromArray(.subarry,k1dict,impBi)
120+
}
121+
quit ret
122+
}
123+
124+
/// Convert IRIS array variable to python dictionary
125+
/// <example>
126+
/// set tlist=$LB(1,2,3,$LB("A","B","C"))
127+
/// set myPyList=##class(Py.Helper).toPyListOrString(tlist)
128+
/// myPyList=59@%SYS.Python ; [1, 2, 3, ['A', 'B', 'C']] ; <OREF>
129+
/// </example>
130+
ClassMethod toPyListOrString(ByRef data, ByRef ret As %SYS.Python = {$$$NULLOREF}, ByRef impBi As %SYS.Python = {##class(%SYS.Python).Import("builtins")}) As %SYS.Python
131+
{
132+
quit:'$LISTVALID(data) data
133+
if ret=$$$NULLOREF {
134+
set ret=impBi.list()
135+
}
136+
set listLen=$ListLength(data)
137+
for i=1:1:listLen {
138+
set nData=$LG(data,i)
139+
if '$LISTVALID(nData) {
140+
do ret.append(nData)
141+
} else {
142+
set l1List=impBi.list()
143+
do ret.append(..toPyListOrString(nData,l1List,impBi))
144+
}
145+
}
146+
quit ret
147+
}
148+
149+
/// Convert Python dictionary to IRIS array
150+
/// <example>
151+
/// USER>zw myPyDict
152+
/// myPyDict=4@%SYS.Python ; {'_value': 123, '1': 456, 'ADDRESS': {1: {'ADD1': 'HouseOrFlatNumber', 'ADD2': 'TownOrCity', 'ADD3': 'CountyOrRegion', 'ADD4': 'Country', 'ADD5': 'ZIPCode'}}, 'FNAME': 'BOB', 'LNAME': 'SMITH', 'ListTest': {1: [1, 2, [3, 4, 'Five']]}} ; <OREF>
153+
///
154+
/// USER>kill echoArray
155+
///
156+
/// USER>do ##class(Py.Helper).ArrayFrompyDict(myPyDict,,.echoArray)
157+
///
158+
/// USER>zw echoArray
159+
/// echoArray=123
160+
/// echoArray(1)=456
161+
/// echoArray("ADDRESS",1,"ADD1")="HouseOrFlatNumber"
162+
/// echoArray("ADDRESS",1,"ADD2")="TownOrCity"
163+
/// echoArray("ADDRESS",1,"ADD3")="CountyOrRegion"
164+
/// echoArray("ADDRESS",1,"ADD4")="Country"
165+
/// echoArray("ADDRESS",1,"ADD5")="ZIPCode"
166+
/// echoArray("FNAME")="BOB"
167+
/// echoArray("LNAME")="SMITH"
168+
/// echoArray("ListTest",1)=$lb(1,2,$lb(3,4,"Five"))
169+
/// </example>
170+
ClassMethod ArrayFrompyDict(ByRef pyDict As %SYS.Python = {$$$NULLOREF}, ByRef impBi As %SYS.Python = {##class(%SYS.Python).Import("builtins")}, ByRef array, msgkeys = "") [ ProcedureBlock = 1 ]
171+
{
172+
quit:'$IsObject(pyDict)
173+
// Itterate over the keys of the Dictionary
174+
set dictKeys=impBi.list(pyDict.keys())
175+
set dictValues=impBi.list(pyDict.values())
176+
set listLen=impBi.len(dictKeys)
177+
for i=1:1:listLen {
178+
kill data
179+
set key=..pyListGet(i,dictKeys)
180+
continue:key="" // Can't use empty string key
181+
set data=..pyListGet(i,dictValues)
182+
if $IsObject(data) {
183+
if ..pyListIs(data) {
184+
set data=..ListFrompyList(data,impBi)
185+
} elseif ..pyDictIs(data) {
186+
kill innerArray
187+
do ..ArrayFrompyDict(data,impBi,.innerArray,msgkeys_"["_key_"]")
188+
} else {
189+
set $ZE="Class "_..%ClassName(1)_" Method ArrayFrompyDict. Unsupported value type """_..pyTypeName(data)_""" at key "_msgkeys_"["_key_"]"
190+
do BACK^%ETN
191+
}
192+
} else {
193+
set data=..toPyListOrString(data)
194+
}
195+
if key="_value" {
196+
set array=data // Strings and Lists
197+
} elseif $Data(innerArray)>1 {
198+
merge array(key)=innerArray // Strings,
199+
kill innerArray
200+
} else {
201+
set array(key)=data // lists and "sub-array"
202+
}
203+
}
204+
quit
205+
}
206+
207+
/// Convert Python list to IRIS list
208+
/// <example>
209+
/// USER>zw myPyList
210+
/// myPyList=7@%SYS.Python ; [1, 2, 3, ['A', 'B', 'C']] ; <OREF>
211+
///
212+
///
213+
/// </example>
214+
ClassMethod ListFrompyList(ByRef pyList As %SYS.Python = {$$$NULLOREF}, ByRef impBi As %SYS.Python = {##class(%SYS.Python).Import("builtins")}, msgkeys = "") As %SYS.Python [ ProcedureBlock = 1 ]
215+
{
216+
set ret=$LB()
217+
// How to get length of list
218+
set listlen=impBi.len(pyList)
219+
for i=1:1:listlen {
220+
set data=##class(Py.Helper).pyListGet(i,pyList)
221+
// if data is also a list // TODO
222+
if $IsObject(data) {
223+
if ..pyListIs(data) {
224+
set data=..ListFrompyList(data,impBi,,msgkeys_"["_i_"]")
225+
} else {
226+
set $ZE="Class "_..%ClassName(1)_" Method ListFrompyList. Unsupported value type """_..pyTypeName(data)_""" at position "_msgkeys_"["_i_"]"
227+
do BACK^%ETN
228+
}
229+
}
230+
// add string / numeric / IRIS LIST to ret
231+
set ret=$LU(ret,i,data)
232+
}
233+
quit ret
234+
}
235+
236+
/// Returns empty string on error
237+
/// position starts at one to keep same as IRIS List
238+
ClassMethod pyListGet(position As %Integer, ByRef pyList As %SYS.Python) As %SYS.Python [ Language = python ]
239+
{
240+
ret=""
241+
try:
242+
ret=(pyList[position-1])
243+
except:
244+
print("Error in pyListGet")
245+
246+
return ret
247+
}
248+
249+
ClassMethod pyListIs(ByRef pyList As %SYS.Python) As %SYS.Python [ Language = python ]
250+
{
251+
return (type(pyList)==list)
252+
}
253+
254+
ClassMethod pyDictIs(ByRef pyDict As %SYS.Python) As %SYS.Python [ Language = python ]
255+
{
256+
return (type(pyDict)==dict)
257+
}
258+
259+
ClassMethod pyTypeName(obj As %SYS.Python) As %String [ Language = python ]
260+
{
261+
return type(obj).__name__
262+
}
263+
264+
}

src/dc/sample/ObjectScript.cls

-11
This file was deleted.

src/dc/sample/PersistentClass.cls

-44
This file was deleted.

0 commit comments

Comments
 (0)