Skip to content

Commit 7e6560e

Browse files
authored
bind: slice elem method auto-wraps the handle, also maps
* fixes issue #191 (slice elem method auto-wraps the handle, including extra tests in slices), and fixes py wrapper imports to include everything referenced. * also wrap handles for map __getitem__ * also rm gopy exe * update after previewing PR: remove gopy.gide, don't print extra py imports, undo one usage change. * one more cmd-exe fix
1 parent 7268a64 commit 7e6560e

File tree

12 files changed

+129
-192
lines changed

12 files changed

+129
-192
lines changed

_examples/slices/slices.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package slices
66

7+
import "fmt"
8+
79
func IntSum(s []int) int {
810
sum := 0
911
for _, value := range s {
@@ -25,3 +27,23 @@ type SliceInt8 []int8
2527
type SliceInt16 []int16
2628
type SliceInt32 []int32
2729
type SliceInt64 []int64
30+
31+
type SliceIface []interface{}
32+
33+
type S struct {
34+
Name string
35+
}
36+
37+
func CreateSSlice() []*S {
38+
return []*S{&S{"S0"}, &S{"S1"}, &S{"S2"}}
39+
}
40+
41+
func PrintSSlice(ss []*S) {
42+
for i, s := range ss {
43+
fmt.Printf("%d: %v\n", i, s.Name)
44+
}
45+
}
46+
47+
func PrintS(s *S) {
48+
fmt.Printf("%v\n", s.Name)
49+
}

_examples/slices/test.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,15 @@
2424
si64 = slices.SliceInt64([-4,-5])
2525
print ("signed slice elements:", si8[0], si16[0], si32[0], si64[0])
2626

27+
ss = slices.CreateSSlice()
28+
print ("struct slice: ", ss)
29+
print ("struct slice[0]: ", ss[0])
30+
print ("struct slice[1]: ", ss[1])
31+
print ("struct slice[2].Name: ", ss[2].Name)
32+
33+
slices.PrintSSlice(ss)
34+
35+
slices.PrintS(ss[0])
36+
slices.PrintS(ss[1])
37+
2738
print("OK")

bind/gen.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ mod.add_include('"%[1]s_go.h"')
192192
mod.add_function('GoPyInit', None, [])
193193
`
194194

195+
// appended to imports in py wrap preamble as key for adding at end
196+
importHereKeyString = "%%%%%%<<<<<<ADDIMPORTSHERE>>>>>>>%%%%%%%"
197+
195198
// 3 = specific package name, 4 = spec pkg path, 5 = doc, 6 = imports
196199
PyWrapPreamble = `%[5]s
197200
# python wrapper for package %[4]s within overall package %[1]s
@@ -451,6 +454,18 @@ func (g *pyGen) genOut() {
451454

452455
func (g *pyGen) genPkgWrapOut() {
453456
g.pywrap.Printf("\n\n")
457+
// note: must generate import string at end as imports can be added during processing
458+
impstr := ""
459+
for _, im := range g.pkg.pyimports {
460+
if g.mode == ModeGen || g.mode == ModeBuild {
461+
impstr += fmt.Sprintf("import %s\n", im)
462+
} else {
463+
impstr += fmt.Sprintf("from %s import %s\n", g.outname, im)
464+
}
465+
}
466+
b := g.pywrap.buf.Bytes()
467+
nb := bytes.Replace(b, []byte(importHereKeyString), []byte(impstr), 1)
468+
g.pywrap.buf = bytes.NewBuffer(nb)
454469
g.genPrintOut(g.pkg.pkg.Name()+".py", g.pywrap)
455470
}
456471

@@ -529,13 +544,10 @@ func (g *pyGen) genPyWrapPreamble() {
529544
for _, im := range imps {
530545
ipath := im.Path()
531546
if _, has := g.pkgmap[ipath]; has {
532-
if g.mode == ModeGen || g.mode == ModeBuild {
533-
impstr += fmt.Sprintf("import %s\n", im.Name())
534-
} else {
535-
impstr += fmt.Sprintf("from %s import %s\n", g.outname, im.Name())
536-
}
547+
g.pkg.AddPyImport(ipath, false)
537548
}
538549
}
550+
impstr += importHereKeyString
539551

540552
if g.mode == ModeExe {
541553
g.pywrap.Printf(PyWrapExePreamble, g.outname, g.cmdstr, n, pkgimport, pkgDoc, impstr)

bind/gen_map.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,17 @@ otherwise parameter is a python list that we copy from
164164
g.pywrap.Printf("def __getitem__(self, key):\n")
165165
g.pywrap.Indent()
166166
if ksym.hasHandle() {
167-
g.pywrap.Printf("return _%s_elem(self.handle, key.handle)\n", qNm)
167+
if esym.hasHandle() {
168+
g.pywrap.Printf("return %s(handle=_%s_elem(self.handle, key.handle))\n", esym.pyPkgId(slc.gopkg), qNm)
169+
} else {
170+
g.pywrap.Printf("return _%s_elem(self.handle, key.handle)\n", qNm)
171+
}
168172
} else {
169-
g.pywrap.Printf("return _%s_elem(self.handle, key)\n", qNm)
173+
if esym.hasHandle() {
174+
g.pywrap.Printf("return %s(handle=_%s_elem(self.handle, key))\n", esym.pyPkgId(slc.gopkg), qNm)
175+
} else {
176+
g.pywrap.Printf("return _%s_elem(self.handle, key)\n", qNm)
177+
}
170178
}
171179
g.pywrap.Outdent()
172180

bind/gen_slice.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,11 @@ otherwise parameter is a python list that we copy from
158158
g.pywrap.Indent()
159159
g.pywrap.Printf("raise IndexError('slice index out of range')\n")
160160
g.pywrap.Outdent()
161-
g.pywrap.Printf("return _%s_elem(self.handle, key)\n", qNm)
161+
if esym.hasHandle() {
162+
g.pywrap.Printf("return %s(handle=_%s_elem(self.handle, key))\n", esym.pyPkgId(slc.gopkg), qNm)
163+
} else {
164+
g.pywrap.Printf("return _%s_elem(self.handle, key)\n", qNm)
165+
}
162166
g.pywrap.Outdent()
163167
g.pywrap.Printf("else:\n")
164168
g.pywrap.Indent()

bind/package.go

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"go/doc"
1010
"go/types"
11+
"path/filepath"
1112
"reflect"
1213
"strings"
1314
)
@@ -20,15 +21,16 @@ type Package struct {
2021
sz types.Sizes
2122
doc *doc.Package
2223

23-
syms *symtab // note: this is now *always* = symbols.current
24-
objs map[string]Object
25-
consts []*Const
26-
vars []*Var
27-
structs []*Struct
28-
ifaces []*Interface
29-
slices []*Slice
30-
maps []*Map
31-
funcs []*Func
24+
syms *symtab // note: this is now *always* = symbols.current
25+
objs map[string]Object
26+
consts []*Const
27+
vars []*Var
28+
structs []*Struct
29+
ifaces []*Interface
30+
slices []*Slice
31+
maps []*Map
32+
funcs []*Func
33+
pyimports map[string]string // extra python imports from incidental python wrapper includes
3234
// calls []*Signature // TODO: could optimize calls back into python to gen once
3335
}
3436

@@ -52,17 +54,19 @@ func NewPackage(pkg *types.Package, doc *doc.Package) (*Package, error) {
5254
fmt.Printf("\n--- Processing package: %v ---\n", pkg.Path())
5355
sz := int64(reflect.TypeOf(int(0)).Size())
5456
p := &Package{
55-
pkg: pkg,
56-
n: 0,
57-
sz: &types.StdSizes{WordSize: sz, MaxAlign: sz},
58-
doc: doc,
59-
syms: current,
60-
objs: map[string]Object{},
57+
pkg: pkg,
58+
n: 0,
59+
sz: &types.StdSizes{WordSize: sz, MaxAlign: sz},
60+
doc: doc,
61+
syms: current,
62+
objs: map[string]Object{},
63+
pyimports: map[string]string{},
6164
}
6265
err := p.process()
6366
if err != nil {
6467
return nil, err
6568
}
69+
6670
Packages = append(Packages, p)
6771
return p, err
6872
}
@@ -77,6 +81,28 @@ func (p *Package) ImportPath() string {
7781
return p.doc.ImportPath
7882
}
7983

84+
// add given path to python imports -- these packages were referenced
85+
func (p *Package) AddPyImport(ipath string, extra bool) {
86+
mypath := p.pkg.Path()
87+
if mypath == "go" {
88+
return
89+
}
90+
if ipath == mypath {
91+
return
92+
}
93+
if p.pyimports == nil {
94+
p.pyimports = make(map[string]string)
95+
}
96+
if _, has := p.pyimports[ipath]; has {
97+
return
98+
}
99+
nm := filepath.Base(ipath)
100+
p.pyimports[ipath] = nm
101+
// if extra {
102+
// fmt.Printf("%v added py import: %v = %v\n", mypath, ipath, nm)
103+
// }
104+
}
105+
80106
// getDoc returns the doc string associated with types.Object
81107
// parent is the name of the containing scope ("" for global scope)
82108
func (p *Package) getDoc(parent string, o types.Object) string {

bind/symbols.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ func (s *symbol) isPtrOrIface() bool {
298298
}
299299

300300
func (s *symbol) hasHandle() bool {
301+
if s.goname == "interface{}" {
302+
return false
303+
}
301304
return !s.isBasic() && !s.isSignature()
302305
}
303306

@@ -356,7 +359,8 @@ func (s *symbol) idname() string {
356359
// pyPkgId returns the python package-qualified version of Id
357360
func (s *symbol) pyPkgId(curPkg *types.Package) string {
358361
pnm := s.gopkg.Name()
359-
if _, has := thePyGen.pkgmap[s.gopkg.Path()]; !has { // external symbols are all in go package
362+
ppath := s.gopkg.Path()
363+
if _, has := thePyGen.pkgmap[ppath]; !has { // external symbols are all in go package
360364
if pnm == "go" {
361365
return s.id
362366
} else {
@@ -368,7 +372,8 @@ func (s *symbol) pyPkgId(curPkg *types.Package) string {
368372
}
369373
if !s.isNamed() && (s.isMap() || s.isSlice() || s.isArray()) {
370374
// idnm := strings.TrimPrefix(s.id[uidx+1:], pnm+"_") // in case it has that redundantly
371-
if s.gopkg.Path() != curPkg.Path() {
375+
if ppath != curPkg.Path() {
376+
thePyGen.pkg.AddPyImport(ppath, true) // ensure that this is included in current package
372377
return pnm + "." + s.id
373378
} else {
374379
return s.id
@@ -379,7 +384,8 @@ func (s *symbol) pyPkgId(curPkg *types.Package) string {
379384
return s.id // shouldn't happen
380385
}
381386
idnm := strings.TrimPrefix(s.id[uidx+1:], pnm+"_") // in case it has that redundantly
382-
if s.gopkg.Path() != curPkg.Path() {
387+
if ppath != curPkg.Path() {
388+
thePyGen.pkg.AddPyImport(ppath, true) // ensure that this is included in current package
383389
return pnm + "." + idnm
384390
} else {
385391
return idnm

cmd_exe.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ exe generates and compiles (C)Python language bindings for a Go package, includi
3131
3232
The primary need for an exe instead of a pkg dynamic library is when the main thread must be used for something other than running the python interpreter, such as for a GUI library where the main thread must be used for running the GUI event loop (e.g., GoGi).
3333
34+
When including multiple packages, list in order of increasing dependency, and use -name arg to give appropriate name.
35+
3436
ex:
3537
$ gopy exe [options] <go-package-name> [other-go-package...]
3638
$ gopy exe github.com/go-python/gopy/_examples/hi

cmd_pkg.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ func gopyMakeCmdPkg() *commander.Command {
2929
Long: `
3030
pkg generates and compiles (C)Python language bindings for a Go package, including subdirectories, and generates python module packaging suitable for distribution. if setup.py file does not yet exist in the target directory, then it along with other default packaging files are created, using arguments. Typically you create initial default versions of these files and then edit them, and after that, only regenerate the go binding files.
3131
32+
When including multiple packages, list in order of increasing dependency, and use -name arg to give appropriate name.
33+
3234
ex:
3335
$ gopy pkg [options] <go-package-name> [other-go-package...]
3436
$ gopy pkg github.com/go-python/gopy/_examples/hi

gopy

-7.01 MB
Binary file not shown.

0 commit comments

Comments
 (0)