diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c454cb --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +go-python3 +========== + +Golang bindings for the C-API of CPython-3. + +This package provides a ``go`` package named "python" under which most of the +``PyXYZ`` functions and macros of the public C-API of CPython have been +exposed. Theoretically, you should be able use https://docs.python.org/3/c-api +and know what to type in your ``go`` program. + +API +--- + +Some functions mix go code and call to Python function. Those functions will +return and `int` and `error` type. The `int` represent the Python result code +and the `error` represent any issue from the Go layer. + +Example: + +`func PyRun_AnyFile(filename string)` open `filename` and then call CPython API +function `int PyRun_AnyFile(FILE *fp, const char *filename)`. + +Therefore its signature is `func PyRun_AnyFile(filename string) (int, error)`, +the `int` represent the error code from the CPython `PyRun_AnyFile` function +and error will be set if we failed to open `filename`. + +If an error is raise before calling th CPython function `int` default to `-1`. diff --git a/high_level_layer.go b/high_level_layer.go index 1df3e41..a27220e 100644 --- a/high_level_layer.go +++ b/high_level_layer.go @@ -10,7 +10,8 @@ import ( ) //Py_Main : https://docs.python.org/3/c-api/veryhigh.html?highlight=pycompilerflags#c.Py_Main -func Py_Main(args []string) int { +// "error" will be set if we fail to call "Py_DecodeLocale" on every "args". +func Py_Main(args []string) (int, error) { argc := C.int(len(args)) argv := make([]*C.wchar_t, argc, argc) for i, arg := range args { @@ -19,32 +20,33 @@ func Py_Main(args []string) int { warg := C.Py_DecodeLocale(carg, nil) if warg == nil { - return -1 + return -1, fmt.Errorf("fail to call Py_DecodeLocale on '%s'", arg) } // Py_DecodeLocale requires a call to PyMem_RawFree to free the memory defer C.PyMem_RawFree(unsafe.Pointer(warg)) argv[i] = warg } - return int(C.Py_Main(argc, (**C.wchar_t)(unsafe.Pointer(&argv[0])))) + return int(C.Py_Main(argc, (**C.wchar_t)(unsafe.Pointer(&argv[0])))), nil } //PyRun_AnyFile : https://docs.python.org/3/c-api/veryhigh.html?highlight=pycompilerflags#c.PyRun_AnyFile -func PyRun_AnyFile(filename string) int { +// "error" will be set if we fail to open "filename". +func PyRun_AnyFile(filename string) (int, error) { cfilename := C.CString(filename) defer C.free(unsafe.Pointer(cfilename)) mode := C.CString("r") defer C.free(unsafe.Pointer(mode)) - cfile := C.fopen(cfilename, mode) - if cfile == nil { - return 1 + cfile, err := C.fopen(cfilename, mode) + if err != nil { + return -1, fmt.Errorf("fail to open '%s': %s", filename, err) } defer C.fclose(cfile) // C.PyRun_AnyFile is a macro, using C.PyRun_AnyFileFlags instead - return int(C.PyRun_AnyFileFlags(cfile, cfilename, nil)) + return int(C.PyRun_AnyFileFlags(cfile, cfilename, nil)), nil } //PyRun_SimpleString : https://docs.python.org/3/c-api/veryhigh.html?highlight=pycompilerflags#c.PyRun_SimpleString