Skip to content

Commit 8ab2cac

Browse files
authored
main,bind,_examples: use absolute package imports and make configurable
This CL fixes an issue with the way python import statements are generated using an realtive current directory approach that is no longer compatible with python3. The default behavior has been updated to default to a dot-relative absolute package import for "go" and compiled extension, and a configuration option has been exposed from the CLI flags down to the bind package. A refactor of configuration options was added to avoid further expanding the number of arguments being passed through the system. Fixes #239
1 parent 6405075 commit 8ab2cac

File tree

17 files changed

+296
-184
lines changed

17 files changed

+296
-184
lines changed

_examples/package/mypkg/mypkg.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright 2015 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// mypkg is a nested package.
6+
package mypkg
7+
8+
func SayHello() string {
9+
return "Hello"
10+
}

_examples/package/mypkg/test.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright 2015 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
5+
## py2/py3 compat
6+
from __future__ import absolute_import, print_function
7+
8+
import mypkg.mypkg
9+
10+
print("mypkg.mypkg.SayHello()...")
11+
print(mypkg.mypkg.SayHello())
12+
print("OK")

bind/bind.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ import (
1212
"os"
1313
)
1414

15+
// BindCfg is a configuration used during binding generation
16+
type BindCfg struct {
17+
// output directory for bindings
18+
OutputDir string
19+
// name of output package (otherwise name of first package is used)
20+
Name string
21+
// code string to run in the go main() function in the cgo library
22+
Main string
23+
// the full command args as a string, without path to exe
24+
Cmd string
25+
// path to python interpreter
26+
VM string
27+
// package prefix used when generating python import statements
28+
PkgPrefix string
29+
}
30+
1531
// ErrorList is a list of errors
1632
type ErrorList []error
1733

bind/gen.go

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -229,15 +229,15 @@ import os,sys,inspect,collections
229229
cwd = os.getcwd()
230230
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
231231
os.chdir(currentdir)
232-
import _%[1]s
232+
%[6]s
233233
os.chdir(cwd)
234234
235235
# to use this code in your end-user python file, import it as follows:
236236
# from %[1]s import %[3]s
237237
# and then refer to everything using %[3]s. prefix
238238
# packages imported by this package listed below:
239239
240-
%[6]s
240+
%[7]s
241241
242242
`
243243

@@ -249,14 +249,15 @@ os.chdir(cwd)
249249
# File is generated by gopy. Do not edit.
250250
# %[2]s
251251
252-
import _%[1]s, collections
252+
import collections
253+
%[6]s
253254
254255
# to use this code in your end-user python file, import it as follows:
255256
# from %[1]s import %[3]s
256257
# and then refer to everything using %[3]s. prefix
257258
# packages imported by this package listed below:
258259
259-
%[6]s
260+
%[7]s
260261
261262
`
262263

@@ -463,15 +464,11 @@ var NoMake = false
463464
// and wrapper .py file(s) that are loaded as the interface to the package with shadow
464465
// python-side classes
465466
// mode = gen, build, pkg, exe
466-
func GenPyBind(mode BuildMode, odir, outname, cmdstr, vm, mainstr, libext, extragccargs string, lang int) error {
467+
func GenPyBind(mode BuildMode, libext, extragccargs string, lang int, cfg *BindCfg) error {
467468
gen := &pyGen{
468469
mode: mode,
469-
odir: odir,
470-
pypkgname: outname,
471-
outname: outname,
472-
cmdstr: cmdstr,
473-
vm: vm,
474-
mainstr: mainstr,
470+
pypkgname: cfg.Name,
471+
cfg: cfg,
475472
libext: libext,
476473
extraGccArgs: extragccargs,
477474
lang: lang,
@@ -497,22 +494,17 @@ type pyGen struct {
497494
err ErrorList
498495
pkgmap map[string]struct{} // map of package paths
499496

500-
mode BuildMode // mode: gen, build, pkg, exe
501-
odir string // output directory
502-
pypkgname string // python package name, for pkg and exe build modes (--name arg there), else = outname
503-
// all global functions in goPreamble are accessed by: pypkgname.FuncName, e.g., IncRef, DecRef
504-
outname string // output (package) name -- for specific current go package
505-
cmdstr string // overall command (embedded in generated files)
506-
vm string // python interpreter
507-
mainstr string // main function code string
497+
mode BuildMode // mode: gen, build, pkg, exe
498+
pypkgname string
499+
cfg *BindCfg
508500
libext string
509501
extraGccArgs string
510502
lang int // c-python api version (2,3)
511503
}
512504

513505
func (g *pyGen) gen() error {
514506
g.pkg = nil
515-
err := os.MkdirAll(g.odir, 0755)
507+
err := os.MkdirAll(g.cfg.OutputDir, 0755)
516508
if err != nil {
517509
return fmt.Errorf("gopy: could not create output directory: %v", err)
518510
}
@@ -549,14 +541,14 @@ func (g *pyGen) genPre() {
549541
if !NoMake {
550542
g.genMakefile()
551543
}
552-
oinit, err := os.Create(filepath.Join(g.odir, "__init__.py"))
544+
oinit, err := os.Create(filepath.Join(g.cfg.OutputDir, "__init__.py"))
553545
g.err.Add(err)
554546
err = oinit.Close()
555547
g.err.Add(err)
556548
}
557549

558550
func (g *pyGen) genPrintOut(outfn string, pr *printer) {
559-
of, err := os.Create(filepath.Join(g.odir, outfn))
551+
of, err := os.Create(filepath.Join(g.cfg.OutputDir, outfn))
560552
g.err.Add(err)
561553
_, err = io.Copy(of, pr)
562554
g.err.Add(err)
@@ -565,10 +557,10 @@ func (g *pyGen) genPrintOut(outfn string, pr *printer) {
565557
}
566558

567559
func (g *pyGen) genOut() {
568-
g.pybuild.Printf("\nmod.generate(open('%v.c', 'w'))\n\n", g.outname)
560+
g.pybuild.Printf("\nmod.generate(open('%v.c', 'w'))\n\n", g.cfg.Name)
569561
g.gofile.Printf("\n\n")
570562
g.genLeaksPostamble()
571-
g.genPrintOut(g.outname+".go", g.gofile)
563+
g.genPrintOut(g.cfg.Name+".go", g.gofile)
572564
g.genPrintOut("patch-leaks.go", g.leakfile)
573565
g.genPrintOut("build.py", g.pybuild)
574566
if !NoMake {
@@ -585,7 +577,7 @@ func (g *pyGen) genPkgWrapOut() {
585577
if g.mode == ModeGen || g.mode == ModeBuild {
586578
impstr += fmt.Sprintf("import %s\n", im)
587579
} else {
588-
impstr += fmt.Sprintf("from %s import %s\n", g.outname, im)
580+
impstr += fmt.Sprintf("from %s import %s\n", g.cfg.Name, im)
589581
}
590582
}
591583
b := g.pywrap.buf.Bytes()
@@ -615,7 +607,7 @@ func (g *pyGen) genGoPreamble() {
615607
pkgimport += fmt.Sprintf("\n\t%q", pi)
616608
}
617609
libcfg := func() string {
618-
pycfg, err := GetPythonConfig(g.vm)
610+
pycfg, err := GetPythonConfig(g.cfg.VM)
619611
if err != nil {
620612
panic(err)
621613
}
@@ -629,29 +621,30 @@ func (g *pyGen) genGoPreamble() {
629621
return pkgcfg
630622
}()
631623

632-
if g.mode == ModeExe && g.mainstr == "" {
633-
g.mainstr = "GoPyMainRun()" // default is just to run main
624+
if g.mode == ModeExe && g.cfg.Main == "" {
625+
g.cfg.Main = "GoPyMainRun()" // default is just to run main
634626
}
635627
exeprec := ""
636628
exeprego := ""
637629
if g.mode == ModeExe {
638-
exeprec = fmt.Sprintf(goExePreambleC, g.outname)
630+
exeprec = fmt.Sprintf(goExePreambleC, g.cfg.Name)
639631
exeprego = goExePreambleGo
640632
}
641-
g.gofile.Printf(goPreamble, g.outname, g.cmdstr, libcfg, GoHandle, CGoHandle, pkgimport, g.mainstr, exeprec, exeprego)
642-
g.gofile.Printf("\n// --- generated code for package: %[1]s below: ---\n\n", g.outname)
633+
g.gofile.Printf(goPreamble, g.cfg.Name, g.cfg.Cmd, libcfg, GoHandle, CGoHandle,
634+
pkgimport, g.cfg.Main, exeprec, exeprego)
635+
g.gofile.Printf("\n// --- generated code for package: %[1]s below: ---\n\n", g.cfg.Name)
643636
}
644637

645638
func (g *pyGen) genLeaksPreamble() {
646-
g.leakfile.Printf(patchLeaksPreamble, g.outname, g.cmdstr)
639+
g.leakfile.Printf(patchLeaksPreamble, g.cfg.Name, g.cfg.Cmd)
647640
}
648641

649642
func (g *pyGen) genLeaksPostamble() {
650643
g.leakfile.Printf(patchLeaksPostamble)
651644
}
652645

653646
func (g *pyGen) genPyBuildPreamble() {
654-
g.pybuild.Printf(PyBuildPreamble, g.outname, g.cmdstr)
647+
g.pybuild.Printf(PyBuildPreamble, g.cfg.Name, g.cfg.Cmd)
655648
}
656649

657650
func (g *pyGen) genPyWrapPreamble() {
@@ -666,14 +659,34 @@ func (g *pyGen) genPyWrapPreamble() {
666659
}
667660

668661
// import other packages for other types that we might use
669-
impstr := ""
662+
var impstr, impgenstr string
663+
impgenNames := []string{"_" + g.cfg.Name, "go"}
670664
switch {
671665
case g.pkg.Name() == "go":
672-
impstr += fmt.Sprintf(GoPkgDefs, g.outname)
666+
if g.cfg.PkgPrefix != "" {
667+
impgenstr += fmt.Sprintf("from %s import %s\n", g.cfg.PkgPrefix, "_"+g.cfg.Name)
668+
} else {
669+
impgenstr += fmt.Sprintf("import %s\n", "_"+g.cfg.Name)
670+
}
671+
impstr += fmt.Sprintf(GoPkgDefs, g.cfg.Name)
673672
case g.mode == ModeGen || g.mode == ModeBuild:
674-
impstr += fmt.Sprintf("import go\n")
673+
if g.cfg.PkgPrefix != "" {
674+
for _, name := range impgenNames {
675+
impgenstr += fmt.Sprintf("from %s import %s\n", g.cfg.PkgPrefix, name)
676+
}
677+
} else {
678+
for _, name := range impgenNames {
679+
impgenstr += fmt.Sprintf("import %s\n", name)
680+
}
681+
}
675682
default:
676-
impstr += fmt.Sprintf("from %s import go\n", g.outname)
683+
pkg := "." + g.cfg.Name
684+
if g.cfg.PkgPrefix != "" {
685+
pkg = g.cfg.PkgPrefix + pkg
686+
}
687+
for _, name := range impgenNames {
688+
impgenstr += fmt.Sprintf("from %s import %s\n", pkg, name)
689+
}
677690
}
678691
imps := g.pkg.pkg.Imports()
679692
for _, im := range imps {
@@ -685,9 +698,9 @@ func (g *pyGen) genPyWrapPreamble() {
685698
impstr += importHereKeyString
686699

687700
if g.mode == ModeExe {
688-
g.pywrap.Printf(PyWrapExePreamble, g.outname, g.cmdstr, n, pkgimport, pkgDoc, impstr)
701+
g.pywrap.Printf(PyWrapExePreamble, g.cfg.Name, g.cfg.Cmd, n, pkgimport, pkgDoc, impgenstr, impstr)
689702
} else {
690-
g.pywrap.Printf(PyWrapPreamble, g.outname, g.cmdstr, n, pkgimport, pkgDoc, impstr)
703+
g.pywrap.Printf(PyWrapPreamble, g.cfg.Name, g.cfg.Cmd, n, pkgimport, pkgDoc, impgenstr, impstr)
691704
}
692705
}
693706

@@ -708,18 +721,18 @@ func CmdStrToMakefile(cmdstr string) string {
708721
}
709722

710723
func (g *pyGen) genMakefile() {
711-
gencmd := strings.Replace(g.cmdstr, "gopy build", "gopy gen", 1)
724+
gencmd := strings.Replace(g.cfg.Cmd, "gopy build", "gopy gen", 1)
712725
gencmd = CmdStrToMakefile(gencmd)
713726

714-
pycfg, err := GetPythonConfig(g.vm)
727+
pycfg, err := GetPythonConfig(g.cfg.VM)
715728
if err != nil {
716729
panic(err)
717730
}
718731

719732
if g.mode == ModeExe {
720-
g.makefile.Printf(MakefileExeTemplate, g.outname, g.cmdstr, gencmd, g.vm, g.libext, pycfg.CFlags, pycfg.LdFlags)
733+
g.makefile.Printf(MakefileExeTemplate, g.cfg.Name, g.cfg.Cmd, gencmd, g.cfg.VM, g.libext, pycfg.CFlags, pycfg.LdFlags)
721734
} else {
722-
g.makefile.Printf(MakefileTemplate, g.outname, g.cmdstr, gencmd, g.vm, g.libext, g.extraGccArgs, pycfg.CFlags, pycfg.LdFlags)
735+
g.makefile.Printf(MakefileTemplate, g.cfg.Name, g.cfg.Cmd, gencmd, g.cfg.VM, g.libext, g.extraGccArgs, pycfg.CFlags, pycfg.LdFlags)
723736
}
724737
}
725738

bind/gen_func.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (g *pyGen) genFuncBody(sym *symbol, fsym *Func) {
240240
}
241241
}
242242

243-
pkgname := g.outname
243+
pkgname := g.cfg.Name
244244

245245
_, gdoc, _ := extractPythonName(fsym.GoName(), fsym.Doc())
246246
ifchandle, gdoc := isIfaceHandle(gdoc)

bind/gen_map.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class %[2]s(%[5]sGoClass):
6161
}
6262

6363
func (g *pyGen) genMapInit(slc *symbol, extTypes, pyWrapOnly bool, mpob *Map) {
64-
pkgname := g.outname
64+
pkgname := g.cfg.Name
6565
slNm := slc.id
6666
qNm := pkgname + "." + slNm
6767
typ := slc.GoType().Underlying().(*types.Map)

bind/gen_slice.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class %[2]s(%[5]sGoClass):
6262
func (g *pyGen) genSliceInit(slc *symbol, extTypes, pyWrapOnly bool, slob *Slice) {
6363
pkgname := slc.gopkg.Name()
6464
slNm := slc.id
65-
qNm := g.outname + "." + slNm // this is only for referring to the _ .go package!
65+
qNm := g.cfg.Name + "." + slNm // this is only for referring to the _ .go package!
6666
var esym *symbol
6767
if typ, ok := slc.GoType().Underlying().(*types.Slice); ok {
6868
esym = current.symtype(typ.Elem())

bind/gen_struct.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class %[1]s(%[4]s):
3636
}
3737

3838
func (g *pyGen) genStructInit(s *Struct) {
39-
pkgname := g.outname
39+
pkgname := g.cfg.Name
4040
qNm := s.GoName()
4141
// strNm := s.obj.Name()
4242

@@ -176,7 +176,7 @@ func (g *pyGen) genStructMembers(s *Struct) {
176176
}
177177

178178
func (g *pyGen) genStructMemberGetter(s *Struct, i int, f types.Object) {
179-
pkgname := g.outname
179+
pkgname := g.cfg.Name
180180
ft := f.Type()
181181
ret := current.symtype(ft)
182182
if ret == nil {
@@ -217,7 +217,7 @@ func (g *pyGen) genStructMemberGetter(s *Struct, i int, f types.Object) {
217217
}
218218

219219
func (g *pyGen) genStructMemberSetter(s *Struct, i int, f types.Object) {
220-
pkgname := g.outname
220+
pkgname := g.cfg.Name
221221
ft := f.Type()
222222
ret := current.symtype(ft)
223223
if ret == nil {

bind/gen_varconst.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func (g *pyGen) genVar(v *Var) {
3434

3535
func (g *pyGen) genVarGetter(v *Var) {
3636
gopkg := g.pkg.Name()
37-
pkgname := g.outname
37+
pkgname := g.cfg.Name
3838
cgoFn := v.Name() // plain name is the getter
3939
qCgoFn := gopkg + "_" + cgoFn
4040
qFn := "_" + pkgname + "." + qCgoFn
@@ -74,7 +74,7 @@ func (g *pyGen) genVarGetter(v *Var) {
7474

7575
func (g *pyGen) genVarSetter(v *Var) {
7676
gopkg := g.pkg.Name()
77-
pkgname := g.outname
77+
pkgname := g.cfg.Name
7878
cgoFn := fmt.Sprintf("Set_%s", v.Name())
7979
qCgoFn := gopkg + "_" + cgoFn
8080
qFn := "_" + pkgname + "." + qCgoFn

0 commit comments

Comments
 (0)