Skip to content

Commit d39a3c4

Browse files
Randall C. O'Reillysbinet
Randall C. O'Reilly
authored andcommitted
added gopy:interface=handle doc directive to interpret interface{} args as handles instead of strings; fix go.nil to be a variable not a class; uncomment RemoveAll for main_test work dir; remove more stuff from maps test out to enable consistency; add tests for go.nil, new interface functionality.
1 parent ac43f20 commit d39a3c4

File tree

10 files changed

+100
-34
lines changed

10 files changed

+100
-34
lines changed

_examples/funcs/funcs.go

+8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ func (fs *FunStruct) OtherMeth(arg1 int, args string) {
3131
fmt.Printf("arg1: %d args: %s\n", arg1, args)
3232
}
3333

34+
func (fs *FunStruct) ObjArg(ofs *FunStruct) {
35+
if ofs == nil {
36+
fmt.Printf("got nil\n")
37+
} else {
38+
fmt.Printf("ofs FieldI: %d FieldS: %s\n", ofs.FieldI, ofs.FieldS)
39+
}
40+
}
41+
3442
var (
3543
F1 func()
3644
F2 Func

_examples/funcs/test.py

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ def CallSelf(self):
4747
print("cls.CallSelf...")
4848
cls.CallSelf()
4949

50+
51+
print("fs.ObjArg with nil")
52+
fs.ObjArg(go.nil)
53+
54+
print("fs.ObjArg with fs")
55+
fs.ObjArg(fs)
56+
5057
# todo: not currently supported:
5158

5259
# print("funcs.F1()...")

_examples/iface/iface.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ type Iface interface {
1515
}
1616

1717
// T implements Iface
18-
type T struct{}
18+
type T struct {
19+
FldI int
20+
FldS string
21+
}
1922

2023
func (t *T) F() {
2124
cpkg.Printf("t.F [CALLED]\n")
@@ -27,3 +30,13 @@ func CallIface(v Iface) {
2730
v.F()
2831
cpkg.Printf("iface.CallIface... [DONE]\n")
2932
}
33+
34+
// by default, interface{} is converted to string (most universal type)
35+
func IfaceString(str interface{}) {
36+
cpkg.Printf("iface as string: %v\n", str)
37+
}
38+
39+
//gopy:interface=handle this magic directive says, treat it as a handle
40+
func IfaceHandle(ifc interface{}) {
41+
cpkg.Printf("iface as handle: %v\n", ifc)
42+
}

_examples/iface/test.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
## py2/py3 compat
66
from __future__ import print_function
77

8-
import iface
8+
import iface, go
99

1010
### test docs
1111
print("doc(iface): %r" % (iface.__doc__,))
@@ -18,4 +18,16 @@
1818
print("iface.CallIface(t)")
1919
iface.CallIface(t)
2020

21+
print('iface.IfaceString("test string"')
22+
iface.IfaceString("test string")
23+
24+
print('iface.IfaceString(str(42))')
25+
iface.IfaceString(str(42))
26+
27+
print('iface.IfaceHandle(t)')
28+
iface.IfaceHandle(t)
29+
30+
print('iface.IfaceHandle(go.nil)')
31+
iface.IfaceHandle(go.nil)
32+
2133
print("OK")

_examples/maps/test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
a = maps.New()
99
b = {1: 3.0, 2: 5.0}
1010

11-
print('map a:', a)
12-
print('map a repr:', a.__repr__())
13-
1411
# set to true to test all the builtin map functionality
1512
# due to the random nature of map access in Go, this will
1613
# cause go test to fail randomly so it is off by default
@@ -19,6 +16,9 @@
1916
testall = False
2017

2118
if testall:
19+
print('map a:', a)
20+
print('map a repr:', a.__repr__())
21+
2222
print('map a keys:', a.keys())
2323
print('map a values:', a.values())
2424
print('map a items:', a.items())

bind/gen.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,12 @@ import collections
230230
231231
class GoClass(object):
232232
"""GoClass is the base class for all GoPy wrapper classes"""
233-
pass
234-
235-
class nil(GoClass):
236-
"""nil is the nil pointer in Go"""
237233
def __init__(self):
238234
self.handle = 0
239-
235+
236+
# use go.nil for nil pointers
237+
nil = GoClass()
238+
240239
def Init():
241240
"""calls the GoPyInit function, which runs the 'main' code string that was passed using -main arg to gopy"""
242241
_%[1]s.GoPyInit()

bind/gen_func.go

+31-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ func (g *pyGen) genFuncSig(sym *symbol, fsym *Func) bool {
1919
return false
2020
}
2121

22-
gname, _, err := extractPythonName(fsym.GoName(), fsym.Doc())
22+
gname, gdoc, err := extractPythonName(fsym.GoName(), fsym.Doc())
2323
if err != nil {
2424
return false
2525
}
26+
ifchandle, gdoc := isIfaceHandle(gdoc)
2627

2728
sig := fsym.sig
2829
args := sig.Params()
@@ -55,11 +56,16 @@ func (g *pyGen) genFuncSig(sym *symbol, fsym *Func) bool {
5556
return false
5657
}
5758
anm := pySafeArg(arg.Name(), i)
58-
goArgs = append(goArgs, fmt.Sprintf("%s %s", anm, sarg.cgoname))
59-
if sarg.cpyname == "PyObject*" {
60-
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s', transfer_ownership=False)", sarg.cpyname, anm))
59+
if ifchandle && arg.sym.goname == "interface{}" {
60+
goArgs = append(goArgs, fmt.Sprintf("%s %s", anm, CGoHandle))
61+
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s')", PyHandle, anm))
6162
} else {
62-
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s')", sarg.cpyname, anm))
63+
goArgs = append(goArgs, fmt.Sprintf("%s %s", anm, sarg.cgoname))
64+
if sarg.cpyname == "PyObject*" {
65+
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s', transfer_ownership=False)", sarg.cpyname, anm))
66+
} else {
67+
pyArgs = append(pyArgs, fmt.Sprintf("param('%s', '%s')", sarg.cpyname, anm))
68+
}
6369
}
6470
wpArgs = append(wpArgs, anm)
6571
}
@@ -138,6 +144,15 @@ func (g *pyGen) genMethod(s *symbol, o *Func) {
138144
}
139145
}
140146

147+
func isIfaceHandle(gdoc string) (bool, string) {
148+
const PythonIface = "\ngopy:interface=handle"
149+
if idx := strings.Index(gdoc, PythonIface); idx > 0 {
150+
gdoc = gdoc[:idx] + gdoc[idx+len(PythonIface)+1:]
151+
return true, gdoc
152+
}
153+
return false, gdoc
154+
}
155+
141156
func (g *pyGen) genFuncBody(sym *symbol, fsym *Func) {
142157
isMethod := (sym != nil)
143158
isIface := false
@@ -153,6 +168,7 @@ func (g *pyGen) genFuncBody(sym *symbol, fsym *Func) {
153168
pkgname := g.outname
154169

155170
_, gdoc, _ := extractPythonName(fsym.GoName(), fsym.Doc())
171+
ifchandle, gdoc := isIfaceHandle(gdoc)
156172

157173
sig := fsym.Signature()
158174
res := sig.Results()
@@ -233,7 +249,9 @@ if err != nil {
233249
for i, arg := range args {
234250
na := ""
235251
anm := pySafeArg(arg.Name(), i)
236-
if arg.sym.isSignature() {
252+
if ifchandle && arg.sym.goname == "interface{}" {
253+
na = fmt.Sprintf(`gopyh.VarFmHandle((gopyh.CGoHandle)(%s), "interface{}")`, anm)
254+
} else if arg.sym.isSignature() {
237255
na = fmt.Sprintf("%s", arg.sym.py2go)
238256
} else {
239257
if arg.sym.py2go != "" {
@@ -243,7 +261,13 @@ if err != nil {
243261
}
244262
}
245263
callArgs = append(callArgs, na)
246-
if arg.sym.hasHandle() {
264+
if arg.sym.goname == "interface{}" {
265+
if ifchandle {
266+
wrapArgs = append(wrapArgs, fmt.Sprintf("%s.handle", anm))
267+
} else {
268+
wrapArgs = append(wrapArgs, anm)
269+
}
270+
} else if arg.sym.hasHandle() {
247271
wrapArgs = append(wrapArgs, fmt.Sprintf("%s.handle", anm))
248272
} else {
249273
wrapArgs = append(wrapArgs, anm)

bind/gen_map.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (g *pyGen) genMapInit(slc *symbol, extTypes, pyWrapOnly bool, mpob *Map) {
7272
keyslt := types.NewSlice(typ.Key())
7373
keyslsym := current.symtype(keyslt)
7474
if keyslsym == nil {
75-
fmt.Printf("nil key slice type!: %n map: %v\n", current.fullTypeString(keyslt), slc.goname)
75+
fmt.Printf("nil key slice type!: %s map: %s\n", current.fullTypeString(keyslt), slc.goname)
7676
return
7777
}
7878
keyslnm := ""

bind/symbols.go

-6
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,6 @@ func isPyCompatVar(v *symbol) error {
106106
if isErrorType(v.gotyp) {
107107
return fmt.Errorf("gopy: var is error type")
108108
}
109-
// if v.gotyp.String() == "interface{}" {
110-
// return fmt.Errorf("gopy: var is interface{}")
111-
// }
112109
if _, isChan := v.gotyp.(*types.Chan); isChan {
113110
return fmt.Errorf("gopy: var is channel type")
114111
}
@@ -129,9 +126,6 @@ func isPyCompatType(typ types.Type) error {
129126
if _, isChan := typ.(*types.Chan); isChan {
130127
return fmt.Errorf("gopy: type is channel type")
131128
}
132-
// if typ.String() == "interface{}" {
133-
// return fmt.Errorf("gopy: type is interface{}")
134-
// }
135129
return nil
136130
}
137131

main_test.go

+19-10
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,18 @@ func TestBindFuncs(t *testing.T) {
232232
testPkg(t, pkg{
233233
path: path,
234234
lang: features[path],
235-
want: []byte(`fs.CallBack(22, cbfun)...
235+
want: []byte(`got nil
236+
ofs FieldI: 42 FieldS: str field
237+
fs.CallBack(22, cbfun)...
236238
in python cbfun: FieldI: 42 FieldS: str field ival: 22 sval: str field
237239
fs.CallBackIf(22, cbfun)...
238240
in python cbfunif: FieldI: 42 FieldS: str field ival: 22 ifval: str field
239241
fs.CallBack(32, cls.ClassFun)...
240242
in python class fun: FieldI: 42 FieldS: str field ival: 32 sval: str field
241243
cls.CallSelf...
242244
in python class fun: FieldI: 42 FieldS: str field ival: 77 sval: str field
245+
fs.ObjArg with nil
246+
fs.ObjArg with fs
243247
OK
244248
`),
245249
})
@@ -436,10 +440,18 @@ func TestBindInterfaces(t *testing.T) {
436440
iface.CallIface...
437441
t.F [CALLED]
438442
iface.CallIface... [DONE]
443+
iface as string: test string
444+
iface as string: 42
445+
iface as handle: &{0 }
446+
iface as handle: <nil>
439447
doc(iface): '\npackage iface tests various aspects of interfaces.\n\n'
440448
t = iface.T()
441449
t.F()
442450
iface.CallIface(t)
451+
iface.IfaceString("test string"
452+
iface.IfaceString(str(42))
453+
iface.IfaceHandle(t)
454+
iface.IfaceHandle(go.nil)
443455
OK
444456
`),
445457
})
@@ -509,18 +521,15 @@ func TestBuiltinMaps(t *testing.T) {
509521
testPkg(t, pkg{
510522
path: path,
511523
lang: features[path],
512-
want: []byte(`map a: maps.Map_int_float64 len: 2 handle: 1 {1=3.0, 2=5.0, }
513-
map a repr: maps.Map_int_float64({1=3.0, 2=5.0, })
514-
map a[1]: 3.0
524+
want: []byte(`map a[1]: 3.0
515525
map a[2]: 5.0
516-
caught error: <built-in function Map_int_float64_elem> returned a result with an error set
517526
maps.Sum from Go map: 8.0
518527
map b: {1: 3.0, 2: 5.0}
519528
maps.Sum from Python dictionary: 8.0
520-
maps.Keys from Go map: go.Slice_int len: 2 handle: 5 [1, 2]
521-
maps.Values from Go map: go.Slice_float64 len: 2 handle: 6 [3.0, 5.0]
522-
maps.Keys from Python dictionary: go.Slice_int len: 2 handle: 8 [1, 2]
523-
maps.Values from Python dictionary: go.Slice_float64 len: 2 handle: 10 [3.0, 5.0]
529+
maps.Keys from Go map: go.Slice_int len: 2 handle: 3 [1, 2]
530+
maps.Values from Go map: go.Slice_float64 len: 2 handle: 4 [3.0, 5.0]
531+
maps.Keys from Python dictionary: go.Slice_int len: 2 handle: 6 [1, 2]
532+
maps.Values from Python dictionary: go.Slice_float64 len: 2 handle: 8 [3.0, 5.0]
524533
deleted 1 from a: maps.Map_int_float64 len: 1 handle: 1 {2=5.0, }
525534
OK
526535
`),
@@ -696,7 +705,7 @@ func testPkgBackend(t *testing.T, pyvm string, table pkg) {
696705
if err != nil {
697706
t.Fatalf("[%s:%s]: could not create workdir: %v\n", pyvm, table.path, err)
698707
}
699-
// defer os.RemoveAll(workdir)
708+
defer os.RemoveAll(workdir)
700709
defer bind.ResetPackages()
701710

702711
// fmt.Printf("building in work dir: %s\n", workdir)

0 commit comments

Comments
 (0)