@@ -203,9 +203,43 @@ func GoPyMainRun() {
203203# File is generated by gopy. Do not edit.
204204# %[2]s
205205
206- from pybindgen import retval, param, Module
206+ from pybindgen import retval, param, Function, Module
207207import sys
208208
209+ class CheckedFunction(Function):
210+ def __init__(self, *a, **kw):
211+ super(CheckedFunction, self).__init__(*a, **kw)
212+ self._failure_expression = kw.get('failure_expression', '')
213+ self._failure_cleanup = kw.get('failure_cleanup', '')
214+
215+ def set_failure_expression(self, expr):
216+ self._failure_expression = expr
217+
218+ def set_failure_cleanup(self, expr):
219+ self._failure_cleanup = expr
220+
221+ def generate_call(self):
222+ super(CheckedFunction, self).generate_call()
223+ check = "PyErr_Occurred()"
224+ if self._failure_expression:
225+ check = "{} && {}".format(self._failure_expression, check)
226+ failure_cleanup = self._failure_cleanup or None
227+ self.before_call.write_error_check(check, failure_cleanup)
228+
229+ def add_checked_function(mod, name, retval, params, failure_expression='', *a, **kw):
230+ fn = CheckedFunction(name, retval, params, *a, **kw)
231+ fn.set_failure_expression(failure_expression)
232+ mod._add_function_obj(fn)
233+ return fn
234+
235+ def add_checked_string_function(mod, name, retval, params, failure_expression='', *a, **kw):
236+ fn = CheckedFunction(name, retval, params, *a, **kw)
237+ fn.set_failure_cleanup('if (retval != NULL) free(retval);')
238+ fn.after_call.add_cleanup_code('free(retval);')
239+ fn.set_failure_expression(failure_expression)
240+ mod._add_function_obj(fn)
241+ return fn
242+
209243mod = Module('_%[1]s')
210244mod.add_include('"%[1]s_go.h"')
211245mod.add_function('GoPyInit', None, [])
@@ -226,6 +260,11 @@ mod.add_function('NumHandles', retval('int'), [])
226260
227261# the following is required to enable dlopen to open the _go.so file
228262import os,sys,inspect,collections
263+ try:
264+ import collections.abc as _collections_abc
265+ except ImportError:
266+ _collections_abc = collections
267+
229268cwd = os.getcwd()
230269currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
231270os.chdir(currentdir)
@@ -250,6 +289,10 @@ os.chdir(cwd)
250289# %[2]s
251290
252291import collections
292+ try:
293+ import collections.abc as _collections_abc
294+ except ImportError:
295+ _collections_abc = collections
253296%[6]s
254297
255298# to use this code in your end-user python file, import it as follows:
@@ -263,6 +306,10 @@ import collections
263306
264307 GoPkgDefs = `
265308import collections
309+ try:
310+ import collections.abc as _collections_abc
311+ except ImportError:
312+ _collections_abc = collections
266313
267314class GoClass(object):
268315 """GoClass is the base class for all GoPy wrapper classes"""
@@ -317,8 +364,6 @@ build:
317364 # use pybindgen to build the %[1]s.c file which are the CPython wrappers to cgo wrappers..
318365 # note: pip install pybindgen to get pybindgen if this fails
319366 $(PYTHON) build.py
320- # patch storage leaks in pybindgen output
321- go run patch-leaks.go %[1]s.c
322367 # build the _%[1]s$(LIBEXT) library that contains the cgo and CPython wrappers
323368 # generated %[1]s.py python wrapper imports this c-code package
324369 $(GCC) %[1]s.c %[6]s %[1]s_go$(LIBEXT) -o _%[1]s$(LIBEXT) $(CFLAGS) $(LDFLAGS) -fPIC --shared -w
@@ -360,91 +405,11 @@ build:
360405 # use pybindgen to build the %[1]s.c file which are the CPython wrappers to cgo wrappers..
361406 # note: pip install pybindgen to get pybindgen if this fails
362407 $(PYTHON) build.py
363- # patch storage leaks in pybindgen output
364- go run patch-leaks.go %[1]s.c
365408 # build the executable
366409 - rm %[1]s_go$(LIBEXT)
367410 $(GOBUILD) -o py%[1]s
368411
369412`
370-
371- patchLeaksPreamble = `// patch-leaks.go for post-processing %[1]s.
372- // File is generated by gopy. Do not edit.
373- // %[2]s
374- // +build ignore
375-
376- package main
377-
378- import (
379- "bufio"
380- "bytes"
381- "io/ioutil"
382- "log"
383- "os"
384- "strings"
385- )
386-
387- const (
388- cStringLine = " py_retval = Py_BuildValue((char *) \"s\", retval);"
389- )
390- var cstringFunctions = []string{
391- `
392-
393- patchLeaksPostamble = `
394- }
395-
396- func isCString(line string, names []string) bool {
397- for _, cfn := range names {
398- if strings.HasPrefix(line, cfn) {
399- return true
400- }
401- }
402- return false
403- }
404-
405- func patchCString(line string, out *bytes.Buffer) bool {
406- out.WriteString(line)
407- out.Write([]byte{'\n'})
408- switch line {
409- case "}":
410- return false
411- case cStringLine:
412- out.WriteString(" free(retval);\n")
413- return false
414- }
415- return true
416- }
417-
418- func main() {
419- file := os.Args[1]
420- buf, err := ioutil.ReadFile(file)
421- if err != nil {
422- log.Fatal(err)
423- }
424- sc := bufio.NewScanner(bytes.NewBuffer(buf))
425- obuf := &bytes.Buffer{}
426- var cstring bool
427- for sc.Scan() {
428- line := sc.Text()
429- if cstring {
430- cstring = patchCString(line, obuf)
431- continue
432- }
433- cstring = isCString(line, cstringFunctions)
434- obuf.WriteString(line)
435- obuf.Write([]byte{'\n'})
436- }
437-
438- if err := sc.Err(); err != nil {
439- log.Fatal(err)
440- }
441-
442- err = ioutil.WriteFile(file, obuf.Bytes(), 0644)
443- if err != nil {
444- log.Fatal(err)
445- }
446- }
447- `
448413)
449414
450415// thePyGen is the current pyGen which is needed in symbols to lookup
@@ -536,7 +501,6 @@ func (g *pyGen) genPre() {
536501 g .makefile = & printer {buf : new (bytes.Buffer ), indentEach : []byte ("\t " )}
537502 }
538503 g .genGoPreamble ()
539- g .genLeaksPreamble ()
540504 g .genPyBuildPreamble ()
541505 if ! NoMake {
542506 g .genMakefile ()
@@ -559,9 +523,7 @@ func (g *pyGen) genPrintOut(outfn string, pr *printer) {
559523func (g * pyGen ) genOut () {
560524 g .pybuild .Printf ("\n mod.generate(open('%v.c', 'w'))\n \n " , g .cfg .Name )
561525 g .gofile .Printf ("\n \n " )
562- g .genLeaksPostamble ()
563526 g .genPrintOut (g .cfg .Name + ".go" , g .gofile )
564- g .genPrintOut ("patch-leaks.go" , g .leakfile )
565527 g .genPrintOut ("build.py" , g .pybuild )
566528 if ! NoMake {
567529 g .makefile .Printf ("\n \n " )
@@ -635,14 +597,6 @@ func (g *pyGen) genGoPreamble() {
635597 g .gofile .Printf ("\n // --- generated code for package: %[1]s below: ---\n \n " , g .cfg .Name )
636598}
637599
638- func (g * pyGen ) genLeaksPreamble () {
639- g .leakfile .Printf (patchLeaksPreamble , g .cfg .Name , g .cfg .Cmd )
640- }
641-
642- func (g * pyGen ) genLeaksPostamble () {
643- g .leakfile .Printf (patchLeaksPostamble )
644- }
645-
646600func (g * pyGen ) genPyBuildPreamble () {
647601 g .pybuild .Printf (PyBuildPreamble , g .cfg .Name , g .cfg .Cmd )
648602}
0 commit comments