@@ -3,14 +3,13 @@ package main
3
3
/*
4
4
#include "starlark.h"
5
5
6
- extern PyObject *ConversionError ;
6
+ extern PyObject *ConversionToStarlarkFailed ;
7
7
*/
8
8
import "C"
9
9
10
10
import (
11
11
"fmt"
12
12
"math/big"
13
- "unsafe"
14
13
15
14
"go.starlark.net/starlark"
16
15
)
@@ -19,19 +18,25 @@ func pythonToStarlarkTuple(obj *C.PyObject) (starlark.Tuple, error) {
19
18
var elems []starlark.Value
20
19
pyiter := C .PyObject_GetIter (obj )
21
20
if pyiter == nil {
22
- return starlark.Tuple {}, fmt .Errorf ("List: couldn 't get iterator" )
21
+ return starlark.Tuple {}, fmt .Errorf ("Couldn 't get iterator for Python tuple " )
23
22
}
24
23
defer C .Py_DecRef (pyiter )
25
24
25
+ index := 0
26
26
for pyvalue := C .PyIter_Next (pyiter ); pyvalue != nil ; pyvalue = C .PyIter_Next (pyiter ) {
27
27
defer C .Py_DecRef (pyvalue )
28
28
29
- value , err := pythonToStarlarkValue (pyvalue )
29
+ value , err := innerPythonToStarlarkValue (pyvalue )
30
30
if err != nil {
31
- return starlark.Tuple {}, err
31
+ return starlark.Tuple {}, fmt . Errorf ( "While converting value at index %v in Python tuple: %v" , index , err )
32
32
}
33
33
34
34
elems = append (elems , value )
35
+ index += 1
36
+ }
37
+
38
+ if C .PyErr_Occurred () != nil {
39
+ return starlark.Tuple {}, fmt .Errorf ("Python exception while converting value at index %v in Python tuple" , index )
35
40
}
36
41
37
42
return starlark .Tuple (elems ), nil
@@ -40,7 +45,7 @@ func pythonToStarlarkTuple(obj *C.PyObject) (starlark.Tuple, error) {
40
45
func pythonToStarlarkBytes (obj * C.PyObject ) (starlark.Bytes , error ) {
41
46
cbytes := C .PyBytes_AsString (obj )
42
47
if cbytes == nil {
43
- return starlark .Bytes ("" ), fmt .Errorf ("Bytes: couldn 't get pointer" )
48
+ return starlark .Bytes ("" ), fmt .Errorf ("Couldn 't get pointer to Python bytes " )
44
49
}
45
50
46
51
return starlark .Bytes (C .GoString (cbytes )), nil
@@ -49,107 +54,120 @@ func pythonToStarlarkBytes(obj *C.PyObject) (starlark.Bytes, error) {
49
54
func pythonToStarlarkList (obj * C.PyObject ) (* starlark.List , error ) {
50
55
len := C .PyObject_Length (obj )
51
56
if len < 0 {
52
- return & starlark.List {}, fmt .Errorf ("List: couldn 't get length of object " )
57
+ return & starlark.List {}, fmt .Errorf ("Couldn 't get size of Python list " )
53
58
}
54
59
55
60
var elems []starlark.Value
56
61
pyiter := C .PyObject_GetIter (obj )
57
62
if pyiter == nil {
58
- return & starlark.List {}, fmt .Errorf ("List: couldn 't get iterator" )
63
+ return & starlark.List {}, fmt .Errorf ("Couldn 't get iterator for Python list " )
59
64
}
60
65
defer C .Py_DecRef (pyiter )
61
66
67
+ index := 0
62
68
for pyvalue := C .PyIter_Next (pyiter ); pyvalue != nil ; pyvalue = C .PyIter_Next (pyiter ) {
63
69
defer C .Py_DecRef (pyvalue )
64
-
65
- value , err := pythonToStarlarkValue (pyvalue )
70
+ value , err := innerPythonToStarlarkValue (pyvalue )
66
71
if err != nil {
67
- return & starlark.List {}, err
72
+ return & starlark.List {}, fmt . Errorf ( "While converting value at index %v in Python list: %v" , index , err )
68
73
}
69
74
70
75
elems = append (elems , value )
76
+ index += 1
77
+ }
78
+
79
+ if C .PyErr_Occurred () != nil {
80
+ return & starlark.List {}, fmt .Errorf ("Python exception while converting value at index %v in Python list" , index )
71
81
}
72
82
73
83
return starlark .NewList (elems ), nil
74
84
}
75
85
76
86
func pythonToStarlarkDict (obj * C.PyObject ) (* starlark.Dict , error ) {
77
- len := C .PyObject_Length (obj )
78
- if len < 0 {
79
- return & starlark.Dict {}, fmt .Errorf ("Dict: couldn 't get length of object " )
87
+ size := C .PyObject_Length (obj )
88
+ if size < 0 {
89
+ return & starlark.Dict {}, fmt .Errorf ("Couldn 't get size of Python dict " )
80
90
}
81
91
82
- dict := starlark .NewDict (int (len ))
92
+ dict := starlark .NewDict (int (size ))
83
93
pyiter := C .PyObject_GetIter (obj )
84
94
if pyiter == nil {
85
- return & starlark.Dict {}, fmt .Errorf ("Dict: couldn 't get iterator" )
95
+ return & starlark.Dict {}, fmt .Errorf ("Couldn 't get iterator for Python dict " )
86
96
}
87
97
defer C .Py_DecRef (pyiter )
88
98
89
99
for pykey := C .PyIter_Next (pyiter ); pykey != nil ; pykey = C .PyIter_Next (pyiter ) {
90
100
defer C .Py_DecRef (pykey )
91
101
102
+ key , err := innerPythonToStarlarkValue (pykey )
103
+ if err != nil {
104
+ return & starlark.Dict {}, fmt .Errorf ("While converting key in Python dict: %v" , err )
105
+ }
106
+
92
107
pyvalue := C .PyObject_GetItem (obj , pykey )
93
108
if pyvalue == nil {
94
- return & starlark.Dict {}, fmt .Errorf ("Dict: couldn 't get value" )
109
+ return & starlark.Dict {}, fmt .Errorf ("Couldn 't get value of key %v in Python dict" , key )
95
110
}
96
111
defer C .Py_DecRef (pyvalue )
97
112
98
- key , err := pythonToStarlarkValue (pykey )
99
- if err != nil {
100
- return & starlark.Dict {}, err
101
- }
102
-
103
- value , err := pythonToStarlarkValue (pyvalue )
113
+ value , err := innerPythonToStarlarkValue (pyvalue )
104
114
if err != nil {
105
- return & starlark.Dict {}, err
115
+ return & starlark.Dict {}, fmt . Errorf ( "While converting value of key %v in Python dict: %v" , key , err )
106
116
}
107
117
108
118
err = dict .SetKey (key , value )
109
119
if err != nil {
110
- return & starlark.Dict {}, err
120
+ return & starlark.Dict {}, fmt . Errorf ( "While setting %v to %v in Starlark dict: %v" , key , value , err )
111
121
}
112
122
}
113
123
124
+ if C .PyErr_Occurred () != nil {
125
+ return & starlark.Dict {}, fmt .Errorf ("Python exception while iterating through Python dict" )
126
+ }
127
+
114
128
return dict , nil
115
129
}
116
130
117
131
func pythonToStarlarkSet (obj * C.PyObject ) (* starlark.Set , error ) {
118
- len := C .PyObject_Length (obj )
119
- if len < 0 {
120
- return & starlark.Set {}, fmt .Errorf ("Set: couldn 't get length of object " )
132
+ size := C .PyObject_Length (obj )
133
+ if size < 0 {
134
+ return & starlark.Set {}, fmt .Errorf ("Couldn 't get size of Python set " )
121
135
}
122
136
123
- set := starlark .NewSet (int (len ))
137
+ set := starlark .NewSet (int (size ))
124
138
pyiter := C .PyObject_GetIter (obj )
125
139
if pyiter == nil {
126
- return & starlark.Set {}, fmt .Errorf ("Set: couldn 't get iterator" )
140
+ return & starlark.Set {}, fmt .Errorf ("Couldn 't get iterator for Python set " )
127
141
}
128
142
defer C .Py_DecRef (pyiter )
129
143
130
144
for pyvalue := C .PyIter_Next (pyiter ); pyvalue != nil ; pyvalue = C .PyIter_Next (pyiter ) {
131
145
defer C .Py_DecRef (pyvalue )
132
146
133
- value , err := pythonToStarlarkValue (pyvalue )
147
+ value , err := innerPythonToStarlarkValue (pyvalue )
134
148
if err != nil {
135
- return & starlark.Set {}, err
149
+ return & starlark.Set {}, fmt . Errorf ( "While converting value in Python set: %v" , err )
136
150
}
137
151
138
152
err = set .Insert (value )
139
153
if err != nil {
140
154
raisePythonException (err )
141
- return & starlark.Set {}, err
155
+ return & starlark.Set {}, fmt . Errorf ( "While inserting %v into Starlark set: %v" , value , err )
142
156
}
143
157
}
144
158
159
+ if C .PyErr_Occurred () != nil {
160
+ return & starlark.Set {}, fmt .Errorf ("Python exception while converting value in Python set to Starlark" )
161
+ }
162
+
145
163
return set , nil
146
164
}
147
165
148
166
func pythonToStarlarkString (obj * C.PyObject ) (starlark.String , error ) {
149
167
var size C.Py_ssize_t
150
168
cstr := C .PyUnicode_AsUTF8AndSize (obj , & size )
151
169
if cstr == nil {
152
- return starlark .String ("" ), fmt .Errorf ("Int: couldn 't convert to C string" )
170
+ return starlark .String ("" ), fmt .Errorf ("Couldn 't convert Python string to C string" )
153
171
}
154
172
155
173
return starlark .String (C .GoString (cstr )), nil
@@ -159,7 +177,7 @@ func pythonToStarlarkInt(obj *C.PyObject) (starlark.Int, error) {
159
177
overflow := C .int (0 )
160
178
longlong := int64 (C .PyLong_AsLongLongAndOverflow (obj , & overflow )) // https://youtu.be/6-1Ue0FFrHY
161
179
if C .PyErr_Occurred () != nil {
162
- return starlark.Int {}, fmt .Errorf ("Int: couldn 't convert to long" )
180
+ return starlark.Int {}, fmt .Errorf ("Couldn 't convert Python int to long" )
163
181
}
164
182
165
183
if overflow == 0 {
@@ -168,14 +186,14 @@ func pythonToStarlarkInt(obj *C.PyObject) (starlark.Int, error) {
168
186
169
187
pystr := C .PyObject_Str (obj )
170
188
if pystr == nil {
171
- return starlark.Int {}, fmt .Errorf ("Int: couldn 't convert to Python string" )
189
+ return starlark.Int {}, fmt .Errorf ("Couldn 't convert Python int to string" )
172
190
}
173
191
defer C .Py_DecRef (pystr )
174
192
175
193
var size C.Py_ssize_t
176
194
cstr := C .PyUnicode_AsUTF8AndSize (pystr , & size )
177
195
if cstr == nil {
178
- return starlark.Int {}, fmt .Errorf ("Int: couldn 't convert to C string" )
196
+ return starlark.Int {}, fmt .Errorf ("Couldn 't convert Python int to C string" )
179
197
}
180
198
181
199
i := new (big.Int )
@@ -186,13 +204,13 @@ func pythonToStarlarkInt(obj *C.PyObject) (starlark.Int, error) {
186
204
func pythonToStarlarkFloat (obj * C.PyObject ) (starlark.Float , error ) {
187
205
cvalue := C .PyFloat_AsDouble (obj )
188
206
if C .PyErr_Occurred () != nil {
189
- return starlark .Float (0 ), fmt .Errorf ("Float: couldn 't conver to double" )
207
+ return starlark .Float (0 ), fmt .Errorf ("Couldn 't convert Python float to double" )
190
208
}
191
209
192
210
return starlark .Float (cvalue ), nil
193
211
}
194
212
195
- func pythonToStarlarkValue (obj * C.PyObject ) (starlark.Value , error ) {
213
+ func innerPythonToStarlarkValue (obj * C.PyObject ) (starlark.Value , error ) {
196
214
var value starlark.Value = nil
197
215
var err error = nil
198
216
@@ -219,24 +237,28 @@ func pythonToStarlarkValue(obj *C.PyObject) (starlark.Value, error) {
219
237
value , err = pythonToStarlarkList (obj )
220
238
case C .cgoPyTuple_Check (obj ) == 1 :
221
239
value , err = pythonToStarlarkTuple (obj )
222
- case C .PyMapping_Check (obj ) == 1 :
223
- value , err = pythonToStarlarkDict (obj )
224
240
case C .PySequence_Check (obj ) == 1 :
225
241
value , err = pythonToStarlarkList (obj )
242
+ case C .PyMapping_Check (obj ) == 1 :
243
+ value , err = pythonToStarlarkDict (obj )
244
+ default :
245
+ err = fmt .Errorf ("Don't know how to convert Python %s to Starlark" , C .GoString (obj .ob_type .tp_name ))
226
246
}
227
247
228
- if value == nil {
229
- if err = = nil {
230
- err = fmt .Errorf ("Can't convert Python %s to Starlark" , C . GoString ( obj . ob_type . tp_name ) )
248
+ if err == nil {
249
+ if C . PyErr_Occurred () ! = nil {
250
+ err = fmt .Errorf ("Python exception while converting to Starlark" )
231
251
}
232
252
}
233
253
254
+ return value , err
255
+ }
256
+
257
+ func pythonToStarlarkValue (obj * C.PyObject ) (starlark.Value , error ) {
258
+ value , err := innerPythonToStarlarkValue (obj )
234
259
if err != nil {
235
- if C .PyErr_Occurred () == nil {
236
- errmsg := C .CString (err .Error ())
237
- defer C .free (unsafe .Pointer (errmsg ))
238
- C .PyErr_SetString (C .ConversionError , errmsg )
239
- }
260
+ handleConversionError (err , C .ConversionToStarlarkFailed )
261
+ return nil , err
240
262
}
241
263
242
264
return value , err
0 commit comments