From c2cf11b44c464b80342c9566b288df735fbd3ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Calixte?= Date: Thu, 6 Dec 2018 15:44:22 -0500 Subject: [PATCH 1/2] PyObject unit tests --- object_test.go | 251 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 object_test.go diff --git a/object_test.go b/object_test.go new file mode 100644 index 0000000..99aef4c --- /dev/null +++ b/object_test.go @@ -0,0 +1,251 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAttrString(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("test") + + assert.True(t, s.HasAttrString("split")) + split := s.GetAttrString("split") + assert.NotNil(t, split) +} + +func TestAttr(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("test") + name := PyUnicode_FromString("split") + + assert.True(t, s.HasAttr(name)) + split := s.GetAttr(name) + assert.NotNil(t, split) +} + +func TestRichCompareBool(t *testing.T) { + Py_Initialize() + + s1 := PyUnicode_FromString("test1") + s2 := PyUnicode_FromString("test2") + + assert.Zero(t, s1.RichCompareBool(s2, Py_EQ)) + + assert.NotZero(t, s1.RichCompareBool(s1, Py_EQ)) + +} + +func TestRichCompare(t *testing.T) { + Py_Initialize() + + s1 := PyUnicode_FromString("test1") + s2 := PyUnicode_FromString("test2") + + b1 := s1.RichCompare(s2, Py_EQ) + defer b1.DecRef() + assert.Equal(t, Py_False, b1) + + b2 := s1.RichCompare(s1, Py_EQ) + assert.Equal(t, Py_True, b2) + defer b2.DecRef() + +} + +func TestRepr(t *testing.T) { + Py_Initialize() + + list := PyList_New(0) + defer list.DecRef() + + repr := list.Repr() + + assert.Equal(t, "[]", PyUnicode_AsUTF8(repr)) +} + +func TestStr(t *testing.T) { + Py_Initialize() + + list := PyList_New(0) + defer list.DecRef() + + str := list.Str() + + assert.Equal(t, "[]", PyUnicode_AsUTF8(str)) +} + +func TestASCII(t *testing.T) { + Py_Initialize() + + list := PyList_New(0) + defer list.DecRef() + + ascii := list.ASCII() + + assert.Equal(t, "[]", PyUnicode_AsUTF8(ascii)) +} + +func TestCallable(t *testing.T) { + Py_Initialize() + + builtins := PyEval_GetBuiltins() + assert.True(t, PyDict_Check(builtins)) + + len := PyDict_GetItemString(builtins, "len") + assert.True(t, PyCallable_Check(len)) + + emptyList := PyList_New(0) + assert.True(t, PyList_Check(emptyList)) + + args := PyTuple_New(1) + defer args.DecRef() + assert.True(t, PyTuple_Check(args)) + + PyTuple_SetItem(args, 0, emptyList) + + length := len.Call(args, nil) + assert.True(t, PyLong_Check(length)) + assert.Equal(t, 0, PyLong_AsLong(length)) + length.DecRef() + + length = len.CallObject(args) + assert.True(t, PyLong_Check(length)) + assert.Equal(t, 0, PyLong_AsLong(length)) + length.DecRef() + + length = len.CallFunctionObjArgs(emptyList) + assert.True(t, PyLong_Check(length)) + assert.Equal(t, 0, PyLong_AsLong(length)) + length.DecRef() + +} + +func TestCallMethod(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("hello world") + assert.True(t, PyUnicode_Check(s)) + defer s.DecRef() + + sep := PyUnicode_FromString(" ") + assert.True(t, PyUnicode_Check(sep)) + defer sep.DecRef() + + split := PyUnicode_FromString("split") + assert.True(t, PyUnicode_Check(split)) + defer split.DecRef() + + words := s.CallMethodObjArgs(split, sep) + assert.True(t, PyList_Check(words)) + defer words.DecRef() + assert.Equal(t, 2, PyList_Size(words)) + + hello := PyList_GetItem(words, 0) + assert.True(t, PyUnicode_Check(hello)) + world := PyList_GetItem(words, 1) + assert.True(t, PyUnicode_Check(world)) + + assert.Equal(t, "hello", PyUnicode_AsUTF8(hello)) + assert.Equal(t, "world", PyUnicode_AsUTF8(world)) + + words.DecRef() + + words = s.CallMethodArgs("split", sep) + assert.True(t, PyList_Check(words)) + defer words.DecRef() + assert.Equal(t, 2, PyList_Size(words)) + + hello = PyList_GetItem(words, 0) + assert.True(t, PyUnicode_Check(hello)) + world = PyList_GetItem(words, 1) + assert.True(t, PyUnicode_Check(world)) + + assert.Equal(t, "hello", PyUnicode_AsUTF8(hello)) + assert.Equal(t, "world", PyUnicode_AsUTF8(world)) + + words.DecRef() + +} + +func TestIsTrue(t *testing.T) { + Py_Initialize() + + b := Py_True.IsTrue() != 0 + assert.True(t, b) + + b = Py_False.IsTrue() != 0 + assert.False(t, b) +} + +func TestNot(t *testing.T) { + Py_Initialize() + + b := Py_True.Not() != 0 + assert.False(t, b) + + b = Py_False.Not() != 0 + assert.True(t, b) +} + +func TestLength(t *testing.T) { + Py_Initialize() + length := 6 + + list := PyList_New(length) + defer list.DecRef() + listLength := list.Length() + + assert.Equal(t, length, listLength) + +} + +func TestLengthHint(t *testing.T) { + Py_Initialize() + length := 6 + + list := PyList_New(length) + defer list.DecRef() + listLength := list.LengthHint(0) + + assert.Equal(t, length, listLength) + +} + +func TestObjectItem(t *testing.T) { + Py_Initialize() + + key := PyUnicode_FromString("key") + defer key.DecRef() + value := PyUnicode_FromString("value") + defer value.DecRef() + + dict := PyDict_New() + err := dict.SetItem(key, value) + assert.Zero(t, err) + + dictValue := dict.GetItem(key) + assert.Equal(t, value, dictValue) + + err = dict.DelItem(key) + assert.Zero(t, err) + +} + +func TestDir(t *testing.T) { + Py_Initialize() + + list := PyList_New(0) + defer list.DecRef() + + dir := list.Dir() + defer dir.DecRef() + + repr := dir.Repr() + defer repr.DecRef() + + assert.Equal(t, "['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']", PyUnicode_AsUTF8(repr)) + +} From d48b3d377835e324589b1762316aaabc68b291fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Calixte?= Date: Thu, 6 Dec 2018 12:18:26 -0500 Subject: [PATCH 2/2] Exception handling --- errors.go | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++ exceptions.go | 119 ++++++++++++++++++++++++++++++++++++ helper.go | 1 - warning.go | 53 ++++++++++++++++ 4 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 errors.go create mode 100644 exceptions.go create mode 100644 warning.go diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..164d184 --- /dev/null +++ b/errors.go @@ -0,0 +1,165 @@ +package python3 + +/* +#include "Python.h" +*/ +import "C" + +import ( + "unsafe" +) + +//PyErr_Clear : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear +func PyErr_Clear() { + C.PyErr_Clear() +} + +//PyErr_PrintEx : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_PrintEx +func PyErr_PrintEx(setSysLastVars bool) { + if setSysLastVars { + C.PyErr_PrintEx(1) + } else { + C.PyErr_PrintEx(0) + } +} + +//PyErr_Print : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Print +func PyErr_Print() { + C.PyErr_PrintEx(1) +} + +//PyErr_WriteUnraisable : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable +func PyErr_WriteUnraisable(obj *PyObject) { + C.PyErr_WriteUnraisable(toc(obj)) +} + +//PyErr_SetString : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetString +func PyErr_SetString(pyType *PyObject, message string) { + cmessage := C.CString(message) + defer C.free(unsafe.Pointer(cmessage)) + + C.PyErr_SetString(toc(pyType), cmessage) + +} + +//PyErr_SetObject : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetObject +func PyErr_SetObject(pyType, value *PyObject) { + C.PyErr_SetObject(toc(pyType), toc(value)) +} + +//PyErr_SetNone : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetNone +func PyErr_SetNone(pyType *PyObject) { + C.PyErr_SetNone(toc(pyType)) +} + +//PyErr_BadArgument : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_BadArgument +func PyErr_BadArgument() { + C.PyErr_BadArgument() +} + +//PyErr_NoMemory : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NoMemory +func PyErr_NoMemory() *PyObject { + return togo(C.PyErr_NoMemory()) +} + +//PyErr_SetImportErrorSubclass : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetImportErrorSubclass +func PyErr_SetImportErrorSubclass(msg, name, path, subclass *PyObject) *PyObject { + return togo(C.PyErr_SetImportErrorSubclass(toc(msg), toc(name), toc(path), toc(subclass))) +} + +//PyErr_SetImportError : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetImportError +func PyErr_SetImportError(msg, name, path *PyObject) *PyObject { + return togo(C.PyErr_SetImportError(toc(msg), toc(name), toc(path))) +} + +//PyErr_SyntaxLocationObject : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SyntaxLocationObject +func PyErr_SyntaxLocationObject(filename *PyObject, lineno, col_offset int) { + C.PyErr_SyntaxLocationObject(toc(filename), C.int(lineno), C.int(col_offset)) +} + +//PyErr_SyntaxLocationEx : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SyntaxLocationEx +func PyErr_SyntaxLocationEx(filename string, lineno, col_offset int) { + cfilename := C.CString(filename) + defer C.free(unsafe.Pointer(cfilename)) + + C.PyErr_SyntaxLocationEx(cfilename, C.int(lineno), C.int(col_offset)) +} + +//PyErr_SyntaxLocation : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SyntaxLocation +func PyErr_SyntaxLocation(filename string, lineno int) { + cfilename := C.CString(filename) + defer C.free(unsafe.Pointer(cfilename)) + + C.PyErr_SyntaxLocation(cfilename, C.int(lineno)) + +} + +//PyErr_BadInternalCall : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_BadInternalCall +func PyErr_BadInternalCall() { + C.PyErr_BadInternalCall() +} + +//PyErr_Occurred : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Occurred +func PyErr_Occurred() *PyObject { + return togo(C.PyErr_Occurred()) +} + +//PyErr_GivenExceptionMatches : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_GivenExceptionMatches +func PyErr_GivenExceptionMatches(given, exc *PyObject) bool { + ret := C.PyErr_GivenExceptionMatches(toc(given), toc(exc)) + return ret == 1 +} + +//PyErr_ExceptionMatches : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_ExceptionMatches +func PyErr_ExceptionMatches(exc *PyObject) bool { + ret := C.PyErr_ExceptionMatches(toc(exc)) + return ret == 1 +} + +//PyErr_Fetch : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Fetch +func PyErr_Fetch() (*PyObject, *PyObject, *PyObject) { + var pyType, value, traceback *C.PyObject + C.PyErr_Fetch(&pyType, &value, &traceback) + return togo(pyType), togo(value), togo(traceback) +} + +//PyErr_Restore : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Restore +func PyErr_Restore(pyType *PyObject, value *PyObject, traceback *PyObject) { + C.PyErr_Restore(toc(pyType), toc(value), toc(traceback)) +} + +//PyErr_NormalizeException : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NormalizeException +func PyErr_NormalizeException(exc, val, tb *PyObject) (*PyObject, *PyObject, *PyObject) { + cexc := toc(exc) + cval := toc(val) + ctb := toc(tb) + C.PyErr_NormalizeException(&cexc, &cval, &ctb) + return togo(cexc), togo(cval), togo(ctb) +} + +//PyErr_GetExcInfo : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_GetExcInfo +func PyErr_GetExcInfo() (*PyObject, *PyObject, *PyObject) { + var pyType, value, traceback *C.PyObject + C.PyErr_GetExcInfo(&pyType, &value, &traceback) + return togo(pyType), togo(value), togo(traceback) +} + +//PyErr_SetExcInfo : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetExcInfo +func PyErr_SetExcInfo(pyType *PyObject, value *PyObject, traceback *PyObject) { + C.PyErr_SetExcInfo(toc(pyType), toc(value), toc(traceback)) +} + +//PyErr_CheckSignals : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_CheckSignals +func PyErr_CheckSignals() int { + return int(C.PyErr_CheckSignals()) +} + +//PyErr_SetInterrupt : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetInterrupt +func PyErr_SetInterrupt() { + C.PyErr_SetInterrupt() +} + +//PySignal_SetWakeupFd : https://docs.python.org/3/c-api/exceptions.html#c.PySignal_SetWakeupFd +func PySignal_SetWakeupFd(fd uintptr) uintptr { + return uintptr(C.PySignal_SetWakeupFd(C.int(fd))) +} diff --git a/exceptions.go b/exceptions.go new file mode 100644 index 0000000..2c7c658 --- /dev/null +++ b/exceptions.go @@ -0,0 +1,119 @@ +package python3 + +/* +#include "Python.h" +*/ +import "C" + +import ( + "unsafe" +) + +/* +All standard Python exceptions are available as global variables whose names are PyExc_ followed by the Python exception name. +These have the type PyObject*; they are all class objects. +*/ +var ( + PyExc_BaseException = togo(C.PyExc_BaseException) + PyExc_Exception = togo(C.PyExc_Exception) + PyExc_ArithmeticError = togo(C.PyExc_ArithmeticError) + PyExc_AssertionError = togo(C.PyExc_AssertionError) + PyExc_AttributeError = togo(C.PyExc_AttributeError) + PyExc_BlockingIOError = togo(C.PyExc_BlockingIOError) + PyExc_BrokenPipeError = togo(C.PyExc_BrokenPipeError) + PyExc_BufferError = togo(C.PyExc_BufferError) + PyExc_ChildProcessError = togo(C.PyExc_ChildProcessError) + PyExc_ConnectionAbortedError = togo(C.PyExc_ConnectionAbortedError) + PyExc_ConnectionError = togo(C.PyExc_ConnectionError) + PyExc_ConnectionRefusedError = togo(C.PyExc_ConnectionRefusedError) + PyExc_ConnectcionResetError = togo(C.PyExc_ConnectionResetError) + PyExc_EOFError = togo(C.PyExc_EOFError) + PyExc_FileExistsError = togo(C.PyExc_FileExistsError) + PyExc_FileNotFoundError = togo(C.PyExc_FileNotFoundError) + PyExc_FloatingPointError = togo(C.PyExc_FloatingPointError) + PyExc_GeneratorExit = togo(C.PyExc_GeneratorExit) + PyExc_ImportError = togo(C.PyExc_ImportError) + PyExc_IndentationError = togo(C.PyExc_IndentationError) + PyExc_IndexError = togo(C.PyExc_IndexError) + PyExc_InterruptedError = togo(C.PyExc_InterruptedError) + PyExc_IsADirectoryError = togo(C.PyExc_IsADirectoryError) + PyExc_KeyError = togo(C.PyExc_KeyError) + PyExc_KeyboardInterrupt = togo(C.PyExc_KeyboardInterrupt) + PyExc_LookupError = togo(C.PyExc_LookupError) + PyExc_MemoryError = togo(C.PyExc_MemoryError) + PyExc_ModuleNotFoundError = togo(C.PyExc_ModuleNotFoundError) + PyExc_NameError = togo(C.PyExc_NameError) + PyExc_NotADirectoryError = togo(C.PyExc_NotADirectoryError) + PyExc_NotImplementedError = togo(C.PyExc_NotImplementedError) + PyExc_OSError = togo(C.PyExc_OSError) + PyExc_OverflowError = togo(C.PyExc_OverflowError) + PyExc_PermissionError = togo(C.PyExc_PermissionError) + PyExc_ProcessLookupError = togo(C.PyExc_ProcessLookupError) + PyExc_RecursionError = togo(C.PyExc_RecursionError) + PyExc_ReferenceError = togo(C.PyExc_ReferenceError) + PyExc_RuntimeError = togo(C.PyExc_RuntimeError) + PyExc_StopAsyncIteration = togo(C.PyExc_StopAsyncIteration) + PyExc_StopIteration = togo(C.PyExc_StopIteration) + PyExc_SyntaxError = togo(C.PyExc_SyntaxError) + PyExc_SystemError = togo(C.PyExc_SystemError) + PyExc_SystemExit = togo(C.PyExc_SystemExit) + PyExc_TabError = togo(C.PyExc_TabError) + PyExc_TimeoutError = togo(C.PyExc_TimeoutError) + PyExc_TypeError = togo(C.PyExc_TypeError) + PyExc_UnboundLocalError = togo(C.PyExc_UnboundLocalError) + PyExc_UnicodeDecodeError = togo(C.PyExc_UnicodeDecodeError) + PyExc_UnicodeEncodeError = togo(C.PyExc_UnicodeEncodeError) + PyExc_UnicodeError = togo(C.PyExc_UnicodeError) + PyExc_UnicodeTranslateError = togo(C.PyExc_UnicodeTranslateError) + PyExc_ValueError = togo(C.PyExc_ValueError) + PyExc_ZeroDivisionError = togo(C.PyExc_ZeroDivisionError) +) + +//PyErr_NewException : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NewException +func PyErr_NewException(name string, base, dict *PyObject) *PyObject { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + return togo(C.PyErr_NewException(cname, toc(base), toc(dict))) +} + +//PyErr_NewExceptionWithDoc : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NewExceptionWithDoc +func PyErr_NewExceptionWithDoc(name, doc string, base, dict *PyObject) *PyObject { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + cdoc := C.CString(doc) + defer C.free(unsafe.Pointer(cdoc)) + + return togo(C.PyErr_NewExceptionWithDoc(cname, cdoc, toc(base), toc(dict))) +} + +//PyException_GetTraceback : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetTraceback +func PyException_GetTraceback(ex *PyObject) *PyObject { + return togo(C.PyException_GetTraceback(toc(ex))) +} + +//PyException_SetTraceback : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetTraceback +func PyException_SetTraceback(ex, tb *PyObject) { + C.PyException_SetTraceback(toc(ex), toc(tb)) +} + +//PyException_GetContext : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetContext +func PyException_GetContext(ex *PyObject) *PyObject { + return togo(C.PyException_GetContext(toc(ex))) +} + +//PyException_SetContext : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetContext +func PyException_SetContext(ex, ctx *PyObject) { + C.PyException_SetContext(toc(ex), toc(ctx)) +} + +//PyException_GetCause : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetCause +func PyException_GetCause(ex *PyObject) *PyObject { + return togo(C.PyException_GetCause(toc(ex))) +} + +//PyException_SetCause : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetCause +func PyException_SetCause(ex, cause *PyObject) { + C.PyException_SetCause(toc(ex), toc(cause)) +} diff --git a/helper.go b/helper.go index 7d6261a..f846f1f 100644 --- a/helper.go +++ b/helper.go @@ -13,4 +13,3 @@ func togo(cobject *C.PyObject) *PyObject { func toc(object *PyObject) *C.PyObject { return (*C.PyObject)(object) } - diff --git a/warning.go b/warning.go new file mode 100644 index 0000000..3ee0a20 --- /dev/null +++ b/warning.go @@ -0,0 +1,53 @@ +package python3 + +/* +#include "Python.h" +*/ +import "C" + +import ( + "unsafe" +) + +/* +All standard Python warning categories are available as global variables whose names are PyExc_ followed by the Python exception name. +These have the type PyObject*; they are all class objects. +*/ +var ( + PyExc_Warning = togo(C.PyExc_Warning) + PyExc_BytesWarning = togo(C.PyExc_BytesWarning) + PyExc_DeprecationWarning = togo(C.PyExc_DeprecationWarning) + PyExc_FutureWarning = togo(C.PyExc_FutureWarning) + PyExc_ImportWarning = togo(C.PyExc_ImportWarning) + PyExc_PendingDeprecationWarning = togo(C.PyExc_PendingDeprecationWarning) + PyExc_ResourceWarning = togo(C.PyExc_ResourceWarning) + PyExc_RuntimeWarning = togo(C.PyExc_RuntimeWarning) + PyExc_SyntaxWarning = togo(C.PyExc_SyntaxWarning) + PyExc_UnicodeWarning = togo(C.PyExc_UnicodeWarning) + PyExc_UserWarning = togo(C.PyExc_UserWarning) +) + +//PyErr_WarnEx : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WarnEx +func PyErr_WarnEx(category *PyObject, message string, stack_level int) int { + cmessage := C.CString(message) + defer C.free(unsafe.Pointer(cmessage)) + + return int(C.PyErr_WarnEx(toc(category), cmessage, C.Py_ssize_t(stack_level))) +} + +//PyErr_WarnExplicitObject : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WarnExplicitObject +func PyErr_WarnExplicitObject(category *PyObject, message *PyObject, filename *PyObject, lineno int, module *PyObject, registry *PyObject) int { + return int(C.PyErr_WarnExplicitObject(toc(category), toc(message), toc(filename), C.int(lineno), toc(module), toc(registry))) +} + +//PyErr_WarnExplicit : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WarnExplicit +func PyErr_WarnExplicit(category *PyObject, message string, filename string, lineno int, module string, registry *PyObject) int { + cmessage := C.CString(message) + defer C.free(unsafe.Pointer(cmessage)) + cfilename := C.CString(filename) + defer C.free(unsafe.Pointer(cfilename)) + cmodule := C.CString(module) + defer C.free(unsafe.Pointer(cmodule)) + + return int(C.PyErr_WarnExplicit(toc(category), cmessage, cfilename, C.int(lineno), cmodule, toc(registry))) +}