├── tests └── test.py ├── CONTRIBUTING.md ├── Gopkg.toml ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── LICENSE-3rdparty.csv ├── .gitignore ├── type_test.go ├── recursion_test.go ├── variadic.h ├── errors_nix.go ├── helper.go ├── boolean_test.go ├── complex_test.go ├── examples ├── python3 │ └── main.go └── list │ └── main.go ├── recursion.go ├── type.go ├── exceptions_test.go ├── warning_test.go ├── boolean.go ├── high_level_layer_test.go ├── LICENSE ├── thread_test.go ├── Gopkg.lock ├── reflection_test.go ├── reflection.go ├── float_test.go ├── complex.go ├── tuple_test.go ├── list_test.go ├── macro.h ├── byte_array_test.go ├── sys_test.go ├── tuple.go ├── bytes_test.go ├── .circleci └── config.yml ├── README.md ├── float.go ├── bytes.go ├── script └── variadic.go ├── high_level_layer.go ├── byte_array.go ├── unicode_test.go ├── module.go ├── dict_test.go ├── sys.go ├── warning.go ├── module_test.go ├── thread.go ├── macro.c ├── list.go ├── lifecycle_test.go ├── unicode.go ├── integer_test.go ├── dict.go ├── integer.go ├── import.go ├── exceptions.go ├── errors.go ├── errors_test.go ├── import_test.go ├── variadic.c ├── object_test.go ├── lifecycle.go └── object.go /tests/test.py: -------------------------------------------------------------------------------- 1 | from io import StringIO 2 | import sys 3 | 4 | sys.stdout = StringIO() 5 | 6 | 7 | print("hello world") -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please, open issues and submit PRs on https://github.com/DataDog/go-python3 using the provided templates. -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | [prune] 2 | go-tests = true 3 | unused-packages = true 4 | 5 | [[constraint]] 6 | name = "github.com/stretchr/testify" 7 | version = "1.2.2" 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Describe what happened:** 2 | 3 | 4 | **Describe what you expected:** 5 | 6 | 7 | **Steps to reproduce the issue:** 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE-3rdparty.csv: -------------------------------------------------------------------------------- 1 | Component,Origin,License,Copyright 2 | test,github.com/stretchr/testify/assert,MIT, 3 | dynamic linking,github.com/python/cpython, Python-2.0,Copyright (c) 2001-2018 Python Software Foundation. All rights reserved. 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | vendor 14 | -------------------------------------------------------------------------------- /type_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestTypeCheck(t *testing.T) { 10 | Py_Initialize() 11 | 12 | assert.True(t, PyType_Check(Type)) 13 | assert.True(t, PyType_CheckExact(Type)) 14 | } 15 | -------------------------------------------------------------------------------- /recursion_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestRecursion(t *testing.T) { 10 | Py_Initialize() 11 | 12 | assert.Zero(t, Py_EnterRecursiveCall("in test function")) 13 | 14 | Py_LeaveRecursiveCall() 15 | 16 | } 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What does this PR do? 2 | 3 | A brief description of the change being made with this pull request. 4 | 5 | ### Motivation 6 | 7 | What inspired you to submit this pull request? 8 | 9 | ### Additional Notes 10 | 11 | Anything else we should know when reviewing? 12 | 13 | -------------------------------------------------------------------------------- /variadic.h: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | #ifndef VARIADIC_H 9 | #define VARIADIC_H 10 | 11 | #include "Python.h" 12 | 13 | PyObject* _go_PyObject_CallFunctionObjArgs(PyObject *callable, int argc, PyObject **args); 14 | PyObject* _go_PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, int argc, PyObject **args); 15 | 16 | #endif -------------------------------------------------------------------------------- /errors_nix.go: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under MIT License. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2018 Datadog, Inc. 5 | 6 | // +build !windows 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | //PySignal_SetWakeupFd : https://docs.python.org/3/c-api/exceptions.html#c.PySignal_SetWakeupFd 16 | func PySignal_SetWakeupFd(fd uintptr) uintptr { 17 | return uintptr(C.PySignal_SetWakeupFd(C.int(fd))) 18 | } 19 | -------------------------------------------------------------------------------- /helper.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | //go:generate go run script/variadic.go 11 | 12 | //#include "Python.h" 13 | import "C" 14 | 15 | //togo converts a *C.PyObject to a *PyObject 16 | func togo(cobject *C.PyObject) *PyObject { 17 | return (*PyObject)(cobject) 18 | } 19 | 20 | func toc(object *PyObject) *C.PyObject { 21 | return (*C.PyObject)(object) 22 | } 23 | -------------------------------------------------------------------------------- /boolean_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestBoolCheck(t *testing.T) { 17 | Py_Initialize() 18 | 19 | assert.True(t, PyBool_Check(Py_True)) 20 | assert.True(t, PyBool_Check(Py_False)) 21 | } 22 | 23 | func TestBoolFromLong(t *testing.T) { 24 | Py_Initialize() 25 | 26 | assert.Equal(t, Py_True, PyBool_FromLong(1)) 27 | assert.Equal(t, Py_False, PyBool_FromLong(0)) 28 | } 29 | -------------------------------------------------------------------------------- /complex_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestComplex(t *testing.T) { 17 | Py_Initialize() 18 | 19 | real := 2. 20 | imaginary := 5. 21 | 22 | complex := PyComplex_FromDoubles(real, imaginary) 23 | assert.True(t, PyComplex_Check(complex)) 24 | assert.True(t, PyComplex_CheckExact(complex)) 25 | defer complex.DecRef() 26 | 27 | assert.Equal(t, real, PyComplex_RealAsDouble(complex)) 28 | assert.Equal(t, imaginary, PyComplex_ImagAsDouble(complex)) 29 | } 30 | -------------------------------------------------------------------------------- /examples/python3/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | 14 | "github.com/DataDog/go-python3" 15 | ) 16 | 17 | func main() { 18 | i, err := python3.Py_Main(os.Args) 19 | if err != nil { 20 | fmt.Printf("error launching the python interpreter: %s\n", err) 21 | os.Exit(1) 22 | } 23 | if i == 1 { 24 | fmt.Println("The interpreter exited due to an exception") 25 | os.Exit(1) 26 | } 27 | if i == 2 { 28 | fmt.Println("The parameter list does not represent a valid Python command line") 29 | os.Exit(1) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /recursion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | 16 | import ( 17 | "unsafe" 18 | ) 19 | 20 | //Py_EnterRecursiveCall : https://docs.python.org/3/c-api/exceptions.html#c.Py_EnterRecursiveCall 21 | func Py_EnterRecursiveCall(where string) int { 22 | cwhere := C.CString(where) 23 | defer C.free(unsafe.Pointer(cwhere)) 24 | 25 | return int(C._go_Py_EnterRecursiveCall(cwhere)) 26 | } 27 | 28 | //Py_LeaveRecursiveCall : https://docs.python.org/3/c-api/exceptions.html#c.Py_LeaveRecursiveCall 29 | func Py_LeaveRecursiveCall() { 30 | C._go_Py_LeaveRecursiveCall() 31 | } 32 | -------------------------------------------------------------------------------- /type.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //Type : https://docs.python.org/3/c-api/type.html#c.PyType_Type 18 | var Type = togo((*C.PyObject)(unsafe.Pointer(&C.PyType_Type))) 19 | 20 | //PyType_Check : https://docs.python.org/3/c-api/type.html#c.PyType_Check 21 | func PyType_Check(o *PyObject) bool { 22 | return C._go_PyType_Check(toc(o)) != 0 23 | } 24 | 25 | //PyType_CheckExact : https://docs.python.org/3/c-api/type.html#c.PyType_CheckExact 26 | func PyType_CheckExact(o *PyObject) bool { 27 | return C._go_PyType_CheckExact(toc(o)) != 0 28 | } 29 | -------------------------------------------------------------------------------- /exceptions_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestExceptionNew(t *testing.T) { 10 | Py_Initialize() 11 | 12 | exc := PyErr_NewException("test_module.TestException", nil, nil) 13 | assert.NotNil(t, exc) 14 | defer exc.DecRef() 15 | } 16 | 17 | func TestExceptionNewDoc(t *testing.T) { 18 | Py_Initialize() 19 | 20 | exc := PyErr_NewExceptionWithDoc("test_module.TestException", "docstring", nil, nil) 21 | assert.NotNil(t, exc) 22 | defer exc.DecRef() 23 | } 24 | 25 | func TestExceptionContext(t *testing.T) { 26 | Py_Initialize() 27 | 28 | exc := PyErr_NewException("test_module.TestException", nil, nil) 29 | assert.NotNil(t, exc) 30 | defer exc.DecRef() 31 | 32 | PyException_SetContext(exc, PyExc_BrokenPipeError) 33 | 34 | assert.Equal(t, PyExc_BrokenPipeError, PyException_GetContext(exc)) 35 | } 36 | -------------------------------------------------------------------------------- /warning_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestWarnEx(t *testing.T) { 10 | Py_Initialize() 11 | 12 | assert.Zero(t, PyErr_WarnEx(PyExc_RuntimeWarning, "test warning", 3)) 13 | } 14 | 15 | func TestWarnExplicitObject(t *testing.T) { 16 | Py_Initialize() 17 | 18 | message := PyUnicode_FromString("test warning") 19 | defer message.DecRef() 20 | 21 | filename := PyUnicode_FromString("test.py") 22 | defer filename.DecRef() 23 | 24 | module := PyUnicode_FromString("test_module") 25 | defer module.DecRef() 26 | 27 | assert.Zero(t, PyErr_WarnExplicitObject(PyExc_RuntimeError, message, filename, 4, module, nil)) 28 | } 29 | 30 | func TestWarnExplicit(t *testing.T) { 31 | Py_Initialize() 32 | 33 | assert.Zero(t, PyErr_WarnExplicit(PyExc_RuntimeError, "test warning", "test.py", 4, "test_module", nil)) 34 | } 35 | -------------------------------------------------------------------------------- /boolean.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | 16 | import ( 17 | "unsafe" 18 | ) 19 | 20 | //python boolean constants 21 | var ( 22 | Py_False = togo(C.Py_False) 23 | Py_True = togo(C.Py_True) 24 | ) 25 | 26 | //Bool : https://docs.python.org/3/c-api/bool.html#c.PyBool_Type 27 | var Bool = togo((*C.PyObject)(unsafe.Pointer(&C.PyBool_Type))) 28 | 29 | //PyBool_Check : https://docs.python.org/3/c-api/bool.html#c.PyBool_Check 30 | func PyBool_Check(o *PyObject) bool { 31 | return C._go_PyBool_Check(toc(o)) != 0 32 | } 33 | 34 | //PyBool_FromLong : https://docs.python.org/3/c-api/bool.html#c.PyBool_FromLong 35 | func PyBool_FromLong(v int) *PyObject { 36 | return togo(C.PyBool_FromLong(C.long(v))) 37 | } 38 | -------------------------------------------------------------------------------- /high_level_layer_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestRunFile(t *testing.T) { 11 | Py_Initialize() 12 | 13 | pyErr, err := PyRun_AnyFile("tests/test.py") 14 | assert.Zero(t, pyErr) 15 | assert.Nil(t, err) 16 | 17 | stdout := PySys_GetObject("stdout") 18 | 19 | result := stdout.CallMethodArgs("getvalue") 20 | defer result.DecRef() 21 | 22 | assert.Equal(t, "hello world\n", PyUnicode_AsUTF8(result)) 23 | } 24 | 25 | func TestRunString(t *testing.T) { 26 | Py_Initialize() 27 | 28 | pythonCode, err := ioutil.ReadFile("tests/test.py") 29 | assert.Nil(t, err) 30 | 31 | assert.Zero(t, PyRun_SimpleString(string(pythonCode))) 32 | 33 | stdout := PySys_GetObject("stdout") 34 | 35 | result := stdout.CallMethodArgs("getvalue") 36 | defer result.DecRef() 37 | 38 | assert.Equal(t, "hello world\n", PyUnicode_AsUTF8(result)) 39 | } 40 | 41 | func TestPyMain(t *testing.T) { 42 | Py_Initialize() 43 | 44 | pyErr, err := Py_Main([]string{"tests/test.py"}) 45 | assert.Zero(t, pyErr) 46 | assert.Nil(t, err) 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Datadog, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /thread_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestThreadInitialization(t *testing.T) { 10 | Py_Initialize() 11 | PyEval_InitThreads() 12 | 13 | assert.True(t, PyEval_ThreadsInitialized()) 14 | 15 | PyEval_ReInitThreads() 16 | } 17 | 18 | func TestGIL(t *testing.T) { 19 | Py_Initialize() 20 | PyEval_InitThreads() 21 | 22 | gil := PyGILState_Ensure() 23 | 24 | assert.True(t, PyGILState_Check()) 25 | 26 | PyGILState_Release(gil) 27 | } 28 | 29 | func TestThreadState(t *testing.T) { 30 | Py_Initialize() 31 | PyEval_InitThreads() 32 | 33 | threadState := PyGILState_GetThisThreadState() 34 | 35 | threadState2 := PyThreadState_Get() 36 | 37 | assert.Equal(t, threadState, threadState2) 38 | 39 | threadState3 := PyThreadState_Swap(threadState) 40 | 41 | assert.Equal(t, threadState, threadState3) 42 | } 43 | 44 | func TestThreadSaveRestore(t *testing.T) { 45 | Py_Initialize() 46 | PyEval_InitThreads() 47 | 48 | threadState := PyEval_SaveThread() 49 | 50 | assert.False(t, PyGILState_Check()) 51 | 52 | PyEval_RestoreThread(threadState) 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" 6 | name = "github.com/davecgh/go-spew" 7 | packages = ["spew"] 8 | pruneopts = "UT" 9 | revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" 10 | version = "v1.1.1" 11 | 12 | [[projects]] 13 | digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" 14 | name = "github.com/pmezard/go-difflib" 15 | packages = ["difflib"] 16 | pruneopts = "UT" 17 | revision = "792786c7400a136282c1664665ae0a8db921c6c2" 18 | version = "v1.0.0" 19 | 20 | [[projects]] 21 | digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83" 22 | name = "github.com/stretchr/testify" 23 | packages = ["assert"] 24 | pruneopts = "UT" 25 | revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" 26 | version = "v1.2.2" 27 | 28 | [solve-meta] 29 | analyzer-name = "dep" 30 | analyzer-version = 1 31 | input-imports = ["github.com/stretchr/testify/assert"] 32 | solver-name = "gps-cdcl" 33 | solver-version = 1 34 | -------------------------------------------------------------------------------- /reflection_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestReflectionBuiltins(t *testing.T) { 10 | Py_Initialize() 11 | 12 | builtins := PyEval_GetBuiltins() 13 | assert.NotNil(t, builtins) 14 | 15 | len := PyDict_GetItemString(builtins, "len") 16 | assert.True(t, PyCallable_Check(len)) 17 | } 18 | 19 | func TestReflectionLocals(t *testing.T) { 20 | Py_Initialize() 21 | 22 | locals := PyEval_GetLocals() 23 | assert.Nil(t, locals) 24 | } 25 | 26 | func TestReflectionGlobals(t *testing.T) { 27 | Py_Initialize() 28 | 29 | globals := PyEval_GetGlobals() 30 | assert.Nil(t, globals) 31 | } 32 | 33 | func TestReflectionFuncName(t *testing.T) { 34 | Py_Initialize() 35 | 36 | builtins := PyEval_GetBuiltins() 37 | assert.NotNil(t, builtins) 38 | 39 | len := PyDict_GetItemString(builtins, "len") 40 | assert.True(t, PyCallable_Check(len)) 41 | 42 | assert.Equal(t, "len", PyEval_GetFuncName(len)) 43 | } 44 | func TestReflectionFuncDesc(t *testing.T) { 45 | Py_Initialize() 46 | 47 | builtins := PyEval_GetBuiltins() 48 | assert.NotNil(t, builtins) 49 | 50 | len := PyDict_GetItemString(builtins, "len") 51 | assert.True(t, PyCallable_Check(len)) 52 | 53 | assert.Equal(t, "()", PyEval_GetFuncDesc(len)) 54 | } 55 | -------------------------------------------------------------------------------- /reflection.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | //PyEval_GetBuiltins : https://docs.python.org/3/c-api/reflection.html?highlight=reflection#c.PyEval_GetBuiltins 16 | func PyEval_GetBuiltins() *PyObject { 17 | return togo(C.PyEval_GetBuiltins()) 18 | } 19 | 20 | //PyEval_GetLocals : https://docs.python.org/3/c-api/reflection.html?highlight=reflection#c.PyEval_GetLocals 21 | func PyEval_GetLocals() *PyObject { 22 | return togo(C.PyEval_GetLocals()) 23 | } 24 | 25 | //PyEval_GetGlobals : https://docs.python.org/3/c-api/reflection.html?highlight=reflection#c.PyEval_GetGlobals 26 | func PyEval_GetGlobals() *PyObject { 27 | return togo(C.PyEval_GetGlobals()) 28 | } 29 | 30 | //PyEval_GetFuncName : https://docs.python.org/3/c-api/reflection.html?highlight=reflection#c.PyEval_GetFuncName 31 | func PyEval_GetFuncName(pyFunc *PyObject) string { 32 | return C.GoString(C.PyEval_GetFuncName(toc(pyFunc))) 33 | } 34 | 35 | //PyEval_GetFuncDesc : https://docs.python.org/3/c-api/reflection.html?highlight=reflection#c.PyEval_GetFuncDesc 36 | func PyEval_GetFuncDesc(pyFunc *PyObject) string { 37 | return C.GoString(C.PyEval_GetFuncDesc(toc(pyFunc))) 38 | } 39 | -------------------------------------------------------------------------------- /examples/list/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | 14 | "github.com/DataDog/go-python3" 15 | ) 16 | 17 | func main() { 18 | python3.Py_Initialize() 19 | 20 | if !python3.Py_IsInitialized() { 21 | fmt.Println("Error initializing the python interpreter") 22 | os.Exit(1) 23 | } 24 | 25 | err := printList() 26 | if err != nil { 27 | fmt.Printf("failed to print the python list: %s\n", err) 28 | } 29 | 30 | python3.Py_Finalize() 31 | } 32 | 33 | func printList() error { 34 | list := python3.PyList_New(5) 35 | 36 | if exc := python3.PyErr_Occurred(); list == nil && exc != nil { 37 | return fmt.Errorf("Fail to create python list object") 38 | } 39 | defer list.DecRef() 40 | 41 | repr, err := pythonRepr(list) 42 | if err != nil { 43 | return fmt.Errorf("fail to get representation of object list") 44 | } 45 | fmt.Printf("python list: %s\n", repr) 46 | 47 | return nil 48 | } 49 | 50 | func pythonRepr(o *python3.PyObject) (string, error) { 51 | if o == nil { 52 | return "", fmt.Errorf("object is nil") 53 | } 54 | 55 | s := o.Repr() 56 | if s == nil { 57 | python3.PyErr_Clear() 58 | return "", fmt.Errorf("failed to call Repr object method") 59 | } 60 | defer s.DecRef() 61 | 62 | return python3.PyUnicode_AsUTF8(s), nil 63 | } 64 | -------------------------------------------------------------------------------- /float_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "math" 12 | "testing" 13 | 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestPyFloatCheck(t *testing.T) { 18 | Py_Initialize() 19 | 20 | pyFloat := PyFloat_FromDouble(345.) 21 | assert.True(t, PyFloat_Check(pyFloat)) 22 | assert.True(t, PyFloat_CheckExact(pyFloat)) 23 | pyFloat.DecRef() 24 | } 25 | 26 | func TestPyFloatFromAsDouble(t *testing.T) { 27 | Py_Initialize() 28 | v := 2354. 29 | pyFloat := PyFloat_FromDouble(v) 30 | assert.NotNil(t, pyFloat) 31 | assert.Equal(t, v, PyFloat_AsDouble(pyFloat)) 32 | pyFloat.DecRef() 33 | } 34 | 35 | func TestPyFloatFromAsString(t *testing.T) { 36 | Py_Initialize() 37 | pyString := PyUnicode_FromString("2354") 38 | defer pyString.DecRef() 39 | 40 | pyFloat := PyFloat_FromString(pyString) 41 | assert.NotNil(t, pyFloat) 42 | assert.Equal(t, 2354., PyFloat_AsDouble(pyFloat)) 43 | pyFloat.DecRef() 44 | } 45 | 46 | func TestPyFloatMinMax(t *testing.T) { 47 | Py_Initialize() 48 | 49 | assert.Equal(t, math.MaxFloat64, PyFloat_GetMax()) 50 | 51 | assert.Equal(t, 2.2250738585072014e-308, PyFloat_GetMin()) 52 | 53 | PyFloat_ClearFreeList() 54 | } 55 | 56 | func TestPyFloatInfo(t *testing.T) { 57 | Py_Initialize() 58 | 59 | assert.NotNil(t, PyFloat_GetInfo()) 60 | } 61 | -------------------------------------------------------------------------------- /complex.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //Complex : https://docs.python.org/3/c-api/complex.html#c.PyComplex_Type 18 | var Complex = togo((*C.PyObject)(unsafe.Pointer(&C.PyComplex_Type))) 19 | 20 | //PyComplex_Check : https://docs.python.org/3/c-api/complex.html#c.PyComplex_Check 21 | func PyComplex_Check(p *PyObject) bool { 22 | return C._go_PyComplex_Check(toc(p)) != 0 23 | } 24 | 25 | //PyComplex_CheckExact : https://docs.python.org/3/c-api/complex.html#c.PyComplex_CheckExact 26 | func PyComplex_CheckExact(p *PyObject) bool { 27 | return C._go_PyComplex_CheckExact(toc(p)) != 0 28 | } 29 | 30 | //PyComplex_FromDoubles : https://docs.python.org/3/c-api/complex.html#c.PyComplex_FromDoubles 31 | func PyComplex_FromDoubles(real, imag float64) *PyObject { 32 | return togo(C.PyComplex_FromDoubles(C.double(real), C.double(imag))) 33 | } 34 | 35 | //PyComplex_RealAsDouble : https://docs.python.org/3/c-api/complex.html#c.PyComplex_RealAsDouble 36 | func PyComplex_RealAsDouble(op *PyObject) float64 { 37 | return float64(C.PyComplex_RealAsDouble(toc(op))) 38 | } 39 | 40 | //PyComplex_ImagAsDouble : https://docs.python.org/3/c-api/complex.html#c.PyComplex_ImagAsDouble 41 | func PyComplex_ImagAsDouble(op *PyObject) float64 { 42 | return float64(C.PyComplex_ImagAsDouble(toc(op))) 43 | } 44 | -------------------------------------------------------------------------------- /tuple_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestTupleCheck(t *testing.T) { 10 | Py_Initialize() 11 | 12 | tuple := PyTuple_New(0) 13 | assert.True(t, PyTuple_Check(tuple)) 14 | assert.True(t, PyTuple_CheckExact(tuple)) 15 | defer tuple.DecRef() 16 | } 17 | 18 | func TestTupleNew(t *testing.T) { 19 | Py_Initialize() 20 | 21 | tuple := PyTuple_New(0) 22 | assert.NotNil(t, tuple) 23 | defer tuple.DecRef() 24 | } 25 | 26 | func TestTupleSize(t *testing.T) { 27 | Py_Initialize() 28 | 29 | size := 45 30 | tuple := PyTuple_New(size) 31 | assert.Equal(t, size, PyTuple_Size(tuple)) 32 | defer tuple.DecRef() 33 | } 34 | 35 | func TestTupleGetSetItem(t *testing.T) { 36 | Py_Initialize() 37 | 38 | s := PyUnicode_FromString("test") 39 | 40 | i := PyLong_FromGoInt(34) 41 | 42 | tuple := PyTuple_New(2) 43 | defer tuple.DecRef() 44 | 45 | assert.Zero(t, PyTuple_SetItem(tuple, 0, s)) 46 | assert.Zero(t, PyTuple_SetItem(tuple, 1, i)) 47 | 48 | assert.Equal(t, i, PyTuple_GetItem(tuple, 1)) 49 | } 50 | 51 | func TestTupleGetSlice(t *testing.T) { 52 | Py_Initialize() 53 | 54 | s := PyUnicode_FromString("test") 55 | 56 | i := PyLong_FromGoInt(34) 57 | 58 | tuple := PyTuple_New(2) 59 | defer tuple.DecRef() 60 | 61 | assert.Zero(t, PyTuple_SetItem(tuple, 0, s)) 62 | assert.Zero(t, PyTuple_SetItem(tuple, 1, i)) 63 | 64 | slice := PyTuple_GetSlice(tuple, 0, 1) 65 | defer slice.DecRef() 66 | 67 | assert.True(t, PyTuple_Check(slice)) 68 | assert.Equal(t, 1, PyTuple_Size(slice)) 69 | assert.Equal(t, s, PyTuple_GetItem(slice, 0)) 70 | } 71 | -------------------------------------------------------------------------------- /list_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestList(t *testing.T) { 10 | Py_Initialize() 11 | 12 | list := PyList_New(0) 13 | assert.True(t, PyList_Check(list)) 14 | assert.True(t, PyList_CheckExact(list)) 15 | defer list.DecRef() 16 | 17 | s := PyUnicode_FromString("hello") 18 | assert.NotNil(t, s) 19 | 20 | i := PyLong_FromGoInt(123) 21 | assert.NotNil(t, i) 22 | 23 | f := PyFloat_FromDouble(123.4) 24 | assert.NotNil(t, f) 25 | 26 | assert.Zero(t, PyList_Append(list, i)) 27 | assert.Zero(t, PyList_Insert(list, 0, s)) 28 | 29 | assert.Equal(t, 2, PyList_Size(list)) 30 | 31 | assert.Zero(t, PyList_SetItem(list, 0, f)) 32 | 33 | assert.Equal(t, f, PyList_GetItem(list, 0)) 34 | 35 | assert.Zero(t, PyList_Sort(list)) 36 | assert.Equal(t, i, PyList_GetItem(list, 0)) 37 | 38 | assert.Zero(t, PyList_Reverse(list)) 39 | assert.Equal(t, f, PyList_GetItem(list, 0)) 40 | 41 | s = PyUnicode_FromString("world") 42 | assert.NotNil(t, s) 43 | 44 | list2 := PyList_New(1) 45 | defer list2.DecRef() 46 | 47 | assert.Zero(t, PyList_SetItem(list2, 0, s)) 48 | 49 | assert.Zero(t, PyList_SetSlice(list, 0, 1, list2)) 50 | 51 | list3 := PyList_GetSlice(list, 0, 1) 52 | assert.NotNil(t, list3) 53 | defer list3.DecRef() 54 | 55 | assert.Equal(t, 1, list2.RichCompareBool(list3, Py_EQ)) 56 | 57 | tuple := PyList_AsTuple(list) 58 | assert.NotNil(t, tuple) 59 | defer tuple.DecRef() 60 | 61 | world := PyTuple_GetItem(tuple, 0) 62 | assert.NotNil(t, world) 63 | 64 | assert.Equal(t, "world", PyUnicode_AsUTF8(world)) 65 | 66 | PyList_ClearFreeList() 67 | 68 | } 69 | -------------------------------------------------------------------------------- /macro.h: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | #ifndef MACRO_H 9 | #define MACRO_H 10 | 11 | #include "Python.h" 12 | 13 | int _go_Py_EnterRecursiveCall(const char *where); 14 | void _go_Py_LeaveRecursiveCall(); 15 | 16 | int _go_PyType_Check(PyObject *o); 17 | int _go_PyType_CheckExact(PyObject *o); 18 | 19 | int _go_PyLong_Check(PyObject *p); 20 | int _go_PyLong_CheckExact(PyObject *p); 21 | 22 | int _go_PyBool_Check(PyObject *o); 23 | 24 | int _go_PyFloat_Check(PyObject *p); 25 | int _go_PyFloat_CheckExact(PyObject *p); 26 | 27 | int _go_PyComplex_Check(PyObject *p); 28 | int _go_PyComplex_CheckExact(PyObject *p); 29 | 30 | int _go_PyBytes_Check(PyObject *o); 31 | int _go_PyBytes_CheckExact(PyObject *o); 32 | 33 | int _go_PyByteArray_Check(PyObject *o); 34 | int _go_PyByteArray_CheckExact(PyObject *o); 35 | 36 | int _go_PyUnicode_Check(PyObject *o); 37 | int _go_PyUnicode_CheckExact(PyObject *o); 38 | 39 | int _go_PyTuple_Check(PyObject *p); 40 | int _go_PyTuple_CheckExact(PyObject *p); 41 | 42 | int _go_PyList_Check(PyObject *p); 43 | int _go_PyList_CheckExact(PyObject *p); 44 | 45 | int _go_PyDict_Check(PyObject *p); 46 | int _go_PyDict_CheckExact(PyObject *p); 47 | 48 | int _go_PyModule_Check(PyObject *p); 49 | int _go_PyModule_CheckExact(PyObject *p); 50 | 51 | int _go_PyObject_DelAttr(PyObject *o, PyObject *attr_name); 52 | int _go_PyObject_DelAttrString(PyObject *o, const char *attr_name); 53 | 54 | int _go_PyObject_TypeCheck(PyObject *o, PyTypeObject *type); 55 | 56 | #endif -------------------------------------------------------------------------------- /byte_array_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestByteArrayCheck(t *testing.T) { 17 | Py_Initialize() 18 | 19 | s1 := "aaaaaaaa" 20 | 21 | array1 := PyByteArray_FromStringAndSize(s1) 22 | assert.True(t, PyByteArray_Check(array1)) 23 | assert.True(t, PyByteArray_CheckExact(array1)) 24 | defer array1.DecRef() 25 | } 26 | 27 | func TestByteArrayFromAsString(t *testing.T) { 28 | Py_Initialize() 29 | 30 | s1 := "aaaaaaaa" 31 | 32 | array1 := PyByteArray_FromStringAndSize(s1) 33 | defer array1.DecRef() 34 | 35 | assert.Equal(t, s1, PyByteArray_AsString(array1)) 36 | } 37 | 38 | func TestByteArrayConcat(t *testing.T) { 39 | Py_Initialize() 40 | 41 | s1 := "aaaaaaaa" 42 | s2 := "bbbbbbbb" 43 | 44 | array1 := PyByteArray_FromStringAndSize(s1) 45 | defer array1.DecRef() 46 | 47 | bytes := PyBytes_FromString(s2) 48 | assert.NotNil(t, bytes) 49 | defer bytes.DecRef() 50 | 51 | array2 := PyByteArray_FromObject(bytes) 52 | assert.NotNil(t, array2) 53 | defer array2.DecRef() 54 | 55 | newArray := PyByteArray_Concat(array1, array2) 56 | defer newArray.DecRef() 57 | 58 | assert.Equal(t, s1+s2, PyByteArray_AsString(newArray)) 59 | } 60 | 61 | func TestByteArrayResize(t *testing.T) { 62 | Py_Initialize() 63 | 64 | s1 := "aaaaaaaa" 65 | 66 | array1 := PyByteArray_FromStringAndSize(s1) 67 | defer array1.DecRef() 68 | 69 | length := 20 70 | PyByteArray_Resize(array1, 20) 71 | 72 | assert.Equal(t, length, PyByteArray_Size(array1)) 73 | } 74 | -------------------------------------------------------------------------------- /sys_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestSysGetSetObject(t *testing.T) { 10 | Py_Initialize() 11 | 12 | platform := PySys_GetObject("platform") 13 | assert.NotNil(t, platform) 14 | assert.True(t, PyUnicode_Check(platform)) 15 | platform.IncRef() 16 | 17 | newPlatform := PyUnicode_FromString("test") 18 | defer newPlatform.DecRef() 19 | 20 | assert.Zero(t, PySys_SetObject("platform", newPlatform)) 21 | 22 | assert.Equal(t, newPlatform, PySys_GetObject("platform")) 23 | 24 | assert.Zero(t, PySys_SetObject("platform", platform)) 25 | } 26 | 27 | func TestSysWarnOption(t *testing.T) { 28 | Py_Finalize() 29 | 30 | assert.Nil(t, PySys_AddWarnOption("ignore")) 31 | 32 | Py_Initialize() 33 | 34 | warnoptions := PySys_GetObject("warnoptions") 35 | assert.Equal(t, "ignore", PyUnicode_AsUTF8(PyList_GetItem(warnoptions, 0))) 36 | 37 | Py_Finalize() 38 | 39 | PySys_ResetWarnOptions() 40 | 41 | Py_Initialize() 42 | 43 | warnoptions = PySys_GetObject("warnoptions") 44 | assert.Zero(t, PyList_Size(warnoptions)) 45 | } 46 | 47 | func TestSysXOption(t *testing.T) { 48 | Py_Finalize() 49 | 50 | assert.Nil(t, PySys_AddXOption("faulthandler")) 51 | 52 | Py_Initialize() 53 | 54 | XOptions := PySys_GetXOptions() 55 | faulthandler := PyDict_GetItemString(XOptions, "faulthandler") 56 | 57 | assert.Equal(t, Py_True, faulthandler) 58 | } 59 | 60 | func TestSysPath(t *testing.T) { 61 | Py_Initialize() 62 | 63 | path := PySys_GetObject("path") 64 | path.IncRef() 65 | 66 | assert.Nil(t, PySys_SetPath("test")) 67 | 68 | newPath := PySys_GetObject("path") 69 | assert.Equal(t, "test", PyUnicode_AsUTF8(PyList_GetItem(newPath, 0))) 70 | 71 | assert.Zero(t, PySys_SetObject("path", path)) 72 | } 73 | -------------------------------------------------------------------------------- /tuple.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //Tuple : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_Type 18 | var Tuple = togo((*C.PyObject)(unsafe.Pointer(&C.PyTuple_Type))) 19 | 20 | //PyTuple_Check : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_Check 21 | func PyTuple_Check(p *PyObject) bool { 22 | return C._go_PyTuple_Check(toc(p)) != 0 23 | } 24 | 25 | //PyTuple_CheckExact : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_CheckExact 26 | func PyTuple_CheckExact(p *PyObject) bool { 27 | return C._go_PyTuple_CheckExact(toc(p)) != 0 28 | } 29 | 30 | //PyTuple_New : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_New 31 | func PyTuple_New(len int) *PyObject { 32 | return togo(C.PyTuple_New(C.Py_ssize_t(len))) 33 | } 34 | 35 | //PyTuple_Size : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_Size 36 | func PyTuple_Size(p *PyObject) int { 37 | return int(C.PyTuple_Size(toc(p))) 38 | } 39 | 40 | //PyTuple_GetItem : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_GetItem 41 | func PyTuple_GetItem(p *PyObject, pos int) *PyObject { 42 | return togo(C.PyTuple_GetItem(toc(p), C.Py_ssize_t(pos))) 43 | } 44 | 45 | //PyTuple_GetSlice : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_GetSlice 46 | func PyTuple_GetSlice(p *PyObject, low, high int) *PyObject { 47 | return togo(C.PyTuple_GetSlice(toc(p), C.Py_ssize_t(low), C.Py_ssize_t(high))) 48 | } 49 | 50 | //PyTuple_SetItem : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_SetItem 51 | func PyTuple_SetItem(p *PyObject, pos int, o *PyObject) int { 52 | return int(C.PyTuple_SetItem(toc(p), C.Py_ssize_t(pos), toc(o))) 53 | } 54 | -------------------------------------------------------------------------------- /bytes_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestBytesCheck(t *testing.T) { 17 | Py_Initialize() 18 | 19 | s1 := "aaaaaaaa" 20 | 21 | bytes1 := PyBytes_FromString(s1) 22 | assert.True(t, PyBytes_Check(bytes1)) 23 | assert.True(t, PyBytes_CheckExact(bytes1)) 24 | defer bytes1.DecRef() 25 | } 26 | 27 | func TestBytesFromAsString(t *testing.T) { 28 | Py_Initialize() 29 | 30 | s1 := "aaaaaaaa" 31 | 32 | bytes1 := PyBytes_FromString(s1) 33 | defer bytes1.DecRef() 34 | 35 | assert.Equal(t, s1, PyBytes_AsString(bytes1)) 36 | } 37 | 38 | func TestBytesSize(t *testing.T) { 39 | Py_Initialize() 40 | 41 | s1 := "aaaaaaaa" 42 | 43 | bytes1 := PyBytes_FromString(s1) 44 | defer bytes1.DecRef() 45 | 46 | assert.Equal(t, 8, PyBytes_Size(bytes1)) 47 | } 48 | 49 | func TestBytesConcat(t *testing.T) { 50 | Py_Initialize() 51 | 52 | s1 := "aaaaaaaa" 53 | s2 := "bbbbbbbb" 54 | 55 | bytes1 := PyBytes_FromString(s1) 56 | 57 | array := PyByteArray_FromStringAndSize(s2) 58 | defer array.DecRef() 59 | 60 | bytes2 := PyBytes_FromObject(array) 61 | assert.NotNil(t, bytes2) 62 | 63 | bytes1 = PyBytes_Concat(bytes1, bytes2) 64 | assert.NotNil(t, bytes1) 65 | defer bytes1.DecRef() 66 | 67 | assert.Equal(t, s1+s2, PyBytes_AsString(bytes1)) 68 | } 69 | 70 | func TestBytesConcatAndDel(t *testing.T) { 71 | Py_Initialize() 72 | 73 | s1 := "aaaaaaaa" 74 | s2 := "bbbbbbbb" 75 | 76 | bytes1 := PyBytes_FromString(s1) 77 | 78 | bytes2 := PyBytes_FromString(s2) 79 | assert.NotNil(t, bytes2) 80 | 81 | bytes1 = PyBytes_ConcatAndDel(bytes1, bytes2) 82 | assert.NotNil(t, bytes1) 83 | defer bytes1.DecRef() 84 | 85 | assert.Equal(t, s1+s2, PyBytes_AsString(bytes1)) 86 | } 87 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | templates: 4 | job_template: &job_template 5 | working_directory: /go/src/github.com/DataDog/go-python3 6 | docker: 7 | - image: golang:1.11.2 8 | 9 | jobs: 10 | # python3.5: 11 | # <<: *job_template 12 | # steps: 13 | # - checkout 14 | # - run: curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 15 | # - run: dep ensure 16 | # - run: echo "deb http://deb.debian.org/debian unstable main" >> /etc/apt/sources.list 17 | # - run: apt-get update && apt-get install -y python3.5-dev 18 | # - run: cp /usr/lib/x86_64-linux-gnu/pkgconfig/python-3.5.pc /usr/lib/x86_64-linux-gnu/pkgconfig/python3.pc 19 | # - run: go test -cover 20 | 21 | # python3.6: 22 | # <<: *job_template 23 | # steps: 24 | # - checkout 25 | # - run: curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 26 | # - run: dep ensure 27 | # - run: echo "deb http://deb.debian.org/debian unstable main" >> /etc/apt/sources.list 28 | # - run: apt-get update && apt-get install -y python3.6-dev 29 | # - run: cp /usr/lib/x86_64-linux-gnu/pkgconfig/python-3.6.pc /usr/lib/x86_64-linux-gnu/pkgconfig/python3.pc 30 | # - run: go test -cover 31 | 32 | python3.7: 33 | <<: *job_template 34 | steps: 35 | - checkout 36 | - run: curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 37 | - run: dep ensure 38 | - run: echo "deb http://deb.debian.org/debian unstable main" >> /etc/apt/sources.list 39 | - run: apt-get update && apt-get install -y python3.7-dev 40 | - run: cp /usr/lib/x86_64-linux-gnu/pkgconfig/python-3.7.pc /usr/lib/x86_64-linux-gnu/pkgconfig/python3.pc 41 | - run: go test -cover 42 | 43 | workflows: 44 | version: 2 45 | build_test_deploy: 46 | jobs: 47 | # Currently we inconditionally bind some newer functions making 3.5 and 3.6 nott working. 48 | # We could later check for python version and readd the tests 49 | # - python3.5 50 | # - python3.6 51 | - python3.7 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This repo will be archived on December 1st 2021. While still readable it will no longer be maintained.** There's a community maintained successor of this project at https://github.com/go-python/cpy3 . 2 | 3 | # go-python3 4 | 5 | **Currently supports python-3.7 only.** 6 | 7 | Golang bindings for the C-API of CPython-3. 8 | 9 | This package provides a ``go`` package named "python" under which most of the 10 | ``PyXYZ`` functions and macros of the public C-API of CPython have been 11 | exposed. Theoretically, you should be able use https://docs.python.org/3/c-api 12 | and know what to type in your ``go`` program. 13 | 14 | 15 | This project was inspired by https://github.com/sbinet/go-python. Go and take a look if we need something for python-2.7! 16 | 17 | # Install 18 | 19 | ## Deps 20 | 21 | We will need `pkg-config` and a working `python3.7` environment to build these 22 | bindings. Make sure you have Python libraries and header files installed as 23 | well (`python3.7-dev` on Debian or `python3-devel` on Centos for example).. 24 | 25 | By default `pkg-config` will look at the `python3` library so if you want to 26 | choose a specific version just symlink `python-X.Y.pc` to `python3.pc` or use 27 | the `PKG_CONFIG_PATH` environment variable. 28 | 29 | ## Go get 30 | 31 | Then simply `go get github.com/DataDog/go-python3` 32 | 33 | # API 34 | 35 | Some functions mix go code and call to Python function. Those functions will 36 | return and `int` and `error` type. The `int` represent the Python result code 37 | and the `error` represent any issue from the Go layer. 38 | 39 | Example: 40 | 41 | `func PyRun_AnyFile(filename string)` open `filename` and then call CPython API 42 | function `int PyRun_AnyFile(FILE *fp, const char *filename)`. 43 | 44 | Therefore its signature is `func PyRun_AnyFile(filename string) (int, error)`, 45 | the `int` represent the error code from the CPython `PyRun_AnyFile` function 46 | and error will be set if we failed to open `filename`. 47 | 48 | If an error is raise before calling th CPython function `int` default to `-1`. 49 | 50 | Take a look at some [examples](examples) 51 | -------------------------------------------------------------------------------- /float.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //Float : https://docs.python.org/3/c-api/float.html#c.PyFloat_Type 18 | var Float = togo((*C.PyObject)(unsafe.Pointer(&C.PyFloat_Type))) 19 | 20 | //PyFloat_Check : https://docs.python.org/3/c-api/float.html#c.PyFloat_Check 21 | func PyFloat_Check(p *PyObject) bool { 22 | return C._go_PyFloat_Check(toc(p)) != 0 23 | } 24 | 25 | //PyFloat_CheckExact : https://docs.python.org/3/c-api/float.html#c.PyFloat_CheckExact 26 | func PyFloat_CheckExact(p *PyObject) bool { 27 | return C._go_PyFloat_CheckExact(toc(p)) != 0 28 | } 29 | 30 | //PyFloat_FromDouble : https://docs.python.org/3/c-api/float.html#c.PyFloat_FromDouble 31 | func PyFloat_FromDouble(v float64) *PyObject { 32 | return togo(C.PyFloat_FromDouble(C.double(v))) 33 | } 34 | 35 | //PyFloat_FromString : https://docs.python.org/3/c-api/float.html#c.PyFloat_FromString 36 | func PyFloat_FromString(str *PyObject) *PyObject { 37 | return togo(C.PyFloat_FromString(toc(str))) 38 | } 39 | 40 | //PyFloat_AsDouble : https://docs.python.org/3/c-api/float.html#c.PyFloat_AsDouble 41 | func PyFloat_AsDouble(obj *PyObject) float64 { 42 | return float64(C.PyFloat_AsDouble(toc(obj))) 43 | } 44 | 45 | //PyFloat_GetInfo : https://docs.python.org/3/c-api/float.html#c.PyFloat_GetInfo 46 | func PyFloat_GetInfo() *PyObject { 47 | return togo(C.PyFloat_GetInfo()) 48 | } 49 | 50 | //PyFloat_GetMax : https://docs.python.org/3/c-api/float.html#c.PyFloat_GetMax 51 | func PyFloat_GetMax() float64 { 52 | return float64(C.PyFloat_GetMax()) 53 | } 54 | 55 | //PyFloat_GetMin : https://docs.python.org/3/c-api/float.html#c.PyFloat_GetMin 56 | func PyFloat_GetMin() float64 { 57 | return float64(C.PyFloat_GetMin()) 58 | } 59 | 60 | //PyFloat_ClearFreeList : https://docs.python.org/3/c-api/float.html#c.PyFloat_ClearFreeList 61 | func PyFloat_ClearFreeList() int { 62 | return int(C.PyFloat_ClearFreeList()) 63 | } 64 | -------------------------------------------------------------------------------- /bytes.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //Bytes : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_Type 18 | var Bytes = togo((*C.PyObject)(unsafe.Pointer(&C.PyBytes_Type))) 19 | 20 | //PyBytes_Check : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_Check 21 | func PyBytes_Check(o *PyObject) bool { 22 | return C._go_PyBytes_Check(toc(o)) != 0 23 | } 24 | 25 | //PyBytes_CheckExact : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_CheckExact 26 | func PyBytes_CheckExact(o *PyObject) bool { 27 | return C._go_PyBytes_CheckExact(toc(o)) != 0 28 | } 29 | 30 | //PyBytes_FromString : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_FromString 31 | func PyBytes_FromString(str string) *PyObject { 32 | cstr := C.CString(str) 33 | defer C.free(unsafe.Pointer(cstr)) 34 | 35 | return togo(C.PyBytes_FromString(cstr)) 36 | } 37 | 38 | //PyBytes_FromObject : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_FromObject 39 | func PyBytes_FromObject(o *PyObject) *PyObject { 40 | return togo(C.PyBytes_FromObject(toc(o))) 41 | } 42 | 43 | //PyBytes_Size : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_Size 44 | func PyBytes_Size(o *PyObject) int { 45 | return int(C.PyBytes_Size(toc(o))) 46 | } 47 | 48 | //PyBytes_AsString : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_AsString 49 | func PyBytes_AsString(o *PyObject) string { 50 | return C.GoStringN(C.PyBytes_AsString(toc(o)), C.int(C.PyBytes_Size(toc(o)))) 51 | } 52 | 53 | //PyBytes_Concat : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_Concat 54 | func PyBytes_Concat(bytes, newpart *PyObject) *PyObject { 55 | cbytes := toc(bytes) 56 | C.PyBytes_Concat(&cbytes, toc(newpart)) 57 | return togo(cbytes) 58 | } 59 | 60 | //PyBytes_ConcatAndDel : https://docs.python.org/3/c-api/bytes.html#c.PyBytes_ConcatAndDel 61 | func PyBytes_ConcatAndDel(bytes, newpart *PyObject) *PyObject { 62 | cbytes := toc(bytes) 63 | C.PyBytes_ConcatAndDel(&cbytes, toc(newpart)) 64 | return togo(cbytes) 65 | } 66 | -------------------------------------------------------------------------------- /script/variadic.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "flag" 12 | "fmt" 13 | "os" 14 | 15 | python "github.com/DataDog/go-python3" 16 | ) 17 | 18 | var ( 19 | output = flag.String("o", "variadic.c", "output file") 20 | caseNumber = flag.Int("n", python.MaxVariadicLength, "number of case in the switch statement") 21 | ) 22 | 23 | func main() { 24 | flag.Parse() 25 | 26 | out, err := os.Create(*output) 27 | if err != nil { 28 | fmt.Printf("Error opening file %s: %s", *output, err) 29 | os.Exit(1) 30 | } 31 | defer out.Close() 32 | _, err = out.WriteString(`/* 33 | Unless explicitly stated otherwise all files in this repository are licensed 34 | under the MIT License. 35 | This product includes software developed at Datadog (https://www.datadoghq.com/). 36 | Copyright 2018 Datadog, Inc. 37 | */ 38 | 39 | `) 40 | if err != nil { 41 | fmt.Printf("Error writing to file %s: %s", *output, err) 42 | os.Exit(1) 43 | } 44 | 45 | out.WriteString("#include \"Python.h\"\n\n") 46 | out.WriteString(renderTemplate(*caseNumber, "PyObject_CallFunctionObjArgs", "callable")) 47 | out.WriteString(renderTemplate(*caseNumber, "PyObject_CallMethodObjArgs", "obj", "name")) 48 | 49 | } 50 | 51 | func renderTemplate(n int, functionName string, pyArgs ...string) string { 52 | template := 53 | `PyObject* _go_%s(%sint argc, PyObject **argv) { 54 | 55 | PyObject *result = NULL; 56 | switch (argc) { 57 | %s } 58 | return result; 59 | } 60 | ` 61 | args := "" 62 | for _, arg := range pyArgs { 63 | args += fmt.Sprintf("PyObject *%s, ", arg) 64 | } 65 | switchTemplate := "" 66 | for i := 0; i < n+1; i++ { 67 | switchTemplate += fmt.Sprintf(" case %d:\n", i) 68 | args := "" 69 | for _, arg := range pyArgs { 70 | args += fmt.Sprintf("%s, ", arg) 71 | } 72 | for j := 0; j < i; j++ { 73 | args += fmt.Sprintf("argv[%d], ", j) 74 | } 75 | args += "NULL" 76 | switchTemplate += fmt.Sprintf(" return %s(%s);\n", functionName, args) 77 | } 78 | return fmt.Sprintf(template, functionName, args, switchTemplate) 79 | } 80 | -------------------------------------------------------------------------------- /high_level_layer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #cgo pkg-config: python3 12 | #include "Python.h" 13 | */ 14 | import "C" 15 | import ( 16 | "fmt" 17 | "unsafe" 18 | ) 19 | 20 | //Py_Main : https://docs.python.org/3/c-api/veryhigh.html?highlight=pycompilerflags#c.Py_Main 21 | // "error" will be set if we fail to call "Py_DecodeLocale" on every "args". 22 | func Py_Main(args []string) (int, error) { 23 | argc := C.int(len(args)) 24 | argv := make([]*C.wchar_t, argc, argc) 25 | for i, arg := range args { 26 | carg := C.CString(arg) 27 | defer C.free(unsafe.Pointer(carg)) 28 | 29 | warg := C.Py_DecodeLocale(carg, nil) 30 | if warg == nil { 31 | return -1, fmt.Errorf("fail to call Py_DecodeLocale on '%s'", arg) 32 | } 33 | // Py_DecodeLocale requires a call to PyMem_RawFree to free the memory 34 | defer C.PyMem_RawFree(unsafe.Pointer(warg)) 35 | argv[i] = warg 36 | } 37 | 38 | return int(C.Py_Main(argc, (**C.wchar_t)(unsafe.Pointer(&argv[0])))), nil 39 | } 40 | 41 | //PyRun_AnyFile : https://docs.python.org/3/c-api/veryhigh.html?highlight=pycompilerflags#c.PyRun_AnyFile 42 | // "error" will be set if we fail to open "filename". 43 | func PyRun_AnyFile(filename string) (int, error) { 44 | cfilename := C.CString(filename) 45 | defer C.free(unsafe.Pointer(cfilename)) 46 | 47 | mode := C.CString("r") 48 | defer C.free(unsafe.Pointer(mode)) 49 | 50 | cfile, err := C.fopen(cfilename, mode) 51 | if err != nil { 52 | return -1, fmt.Errorf("fail to open '%s': %s", filename, err) 53 | } 54 | defer C.fclose(cfile) 55 | 56 | // C.PyRun_AnyFile is a macro, using C.PyRun_AnyFileFlags instead 57 | return int(C.PyRun_AnyFileFlags(cfile, cfilename, nil)), nil 58 | } 59 | 60 | //PyRun_SimpleString : https://docs.python.org/3/c-api/veryhigh.html?highlight=pycompilerflags#c.PyRun_SimpleString 61 | func PyRun_SimpleString(command string) int { 62 | ccommand := C.CString(command) 63 | defer C.free(unsafe.Pointer(ccommand)) 64 | 65 | // C.PyRun_SimpleString is a macro, using C.PyRun_SimpleStringFlags instead 66 | return int(C.PyRun_SimpleStringFlags(ccommand, nil)) 67 | } 68 | -------------------------------------------------------------------------------- /byte_array.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //ByteArray : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_Type 18 | var ByteArray = togo((*C.PyObject)(unsafe.Pointer(&C.PyByteArray_Type))) 19 | 20 | //PyByteArray_Check : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_Check 21 | func PyByteArray_Check(o *PyObject) bool { 22 | return C._go_PyByteArray_Check(toc(o)) != 0 23 | } 24 | 25 | //PyByteArray_CheckExact : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_CheckExact 26 | func PyByteArray_CheckExact(o *PyObject) bool { 27 | return C._go_PyByteArray_CheckExact(toc(o)) != 0 28 | } 29 | 30 | //PyByteArray_FromObject : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_FromObject 31 | func PyByteArray_FromObject(o *PyObject) *PyObject { 32 | return togo(C.PyByteArray_FromObject(toc(o))) 33 | } 34 | 35 | //PyByteArray_FromStringAndSize : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_FromStringAndSize 36 | func PyByteArray_FromStringAndSize(str string) *PyObject { 37 | cstr := C.CString(str) 38 | defer C.free(unsafe.Pointer(cstr)) 39 | 40 | return togo(C.PyByteArray_FromStringAndSize(cstr, C.Py_ssize_t(len(str)))) 41 | } 42 | 43 | //PyByteArray_Concat : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_Concat 44 | func PyByteArray_Concat(a, b *PyObject) *PyObject { 45 | return togo(C.PyByteArray_Concat(toc(a), toc(b))) 46 | } 47 | 48 | //PyByteArray_Size : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_Size 49 | func PyByteArray_Size(o *PyObject) int { 50 | return int(C.PyByteArray_Size(toc(o))) 51 | } 52 | 53 | //PyByteArray_AsString : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_AsString 54 | func PyByteArray_AsString(o *PyObject) string { 55 | return C.GoStringN(C.PyByteArray_AsString(toc(o)), C.int(C.PyByteArray_Size(toc(o)))) 56 | } 57 | 58 | //PyByteArray_Resize : https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_Resize 59 | func PyByteArray_Resize(bytearray *PyObject, len int) { 60 | C.PyByteArray_Resize(toc(bytearray), C.Py_ssize_t(len)) 61 | } 62 | -------------------------------------------------------------------------------- /unicode_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestUnicodeNew(t *testing.T) { 10 | Py_Initialize() 11 | 12 | s := PyUnicode_New(20, 'z') 13 | assert.NotNil(t, s) 14 | defer s.DecRef() 15 | } 16 | 17 | func TestUnicodeFromString(t *testing.T) { 18 | Py_Initialize() 19 | 20 | u := PyUnicode_FromString("aaa") 21 | assert.True(t, PyUnicode_Check(u)) 22 | assert.True(t, PyUnicode_CheckExact(u)) 23 | defer u.DecRef() 24 | 25 | assert.Equal(t, 3, PyUnicode_GetLength(u)) 26 | } 27 | 28 | func TestUnicodeFromEncodedObject(t *testing.T) { 29 | Py_Initialize() 30 | 31 | b := PyBytes_FromString("bbb") 32 | assert.NotNil(t, b) 33 | defer b.DecRef() 34 | ub := PyUnicode_FromEncodedObject(b, "utf-8", "strict") 35 | assert.NotNil(t, ub) 36 | defer ub.DecRef() 37 | } 38 | 39 | func TestUnicodeChar(t *testing.T) { 40 | Py_Initialize() 41 | 42 | u := PyUnicode_FromString("aaa") 43 | assert.True(t, PyUnicode_Check(u)) 44 | assert.True(t, PyUnicode_CheckExact(u)) 45 | defer u.DecRef() 46 | 47 | assert.Equal(t, 0, PyUnicode_WriteChar(u, 1, 'd')) 48 | 49 | assert.Equal(t, 'd', PyUnicode_ReadChar(u, 1)) 50 | } 51 | 52 | func TestUnicodeFill(t *testing.T) { 53 | Py_Initialize() 54 | 55 | u := PyUnicode_FromString("aaa") 56 | assert.True(t, PyUnicode_Check(u)) 57 | assert.True(t, PyUnicode_CheckExact(u)) 58 | defer u.DecRef() 59 | 60 | assert.Equal(t, 3, PyUnicode_Fill(u, 0, 3, 'c')) 61 | 62 | assert.Equal(t, "ccc", PyUnicode_AsUTF8(u)) 63 | } 64 | 65 | func TestUnicodeCopyCharacters(t *testing.T) { 66 | Py_Initialize() 67 | 68 | u := PyUnicode_FromString("aaa") 69 | assert.True(t, PyUnicode_Check(u)) 70 | assert.True(t, PyUnicode_CheckExact(u)) 71 | defer u.DecRef() 72 | 73 | b := PyBytes_FromString("bbb") 74 | assert.NotNil(t, b) 75 | defer b.DecRef() 76 | ub := PyUnicode_FromEncodedObject(b, "utf-8", "strict") 77 | assert.NotNil(t, ub) 78 | defer ub.DecRef() 79 | 80 | assert.Equal(t, 3, PyUnicode_CopyCharacters(ub, u, 0, 0, 3)) 81 | 82 | assert.Equal(t, "aaa", PyUnicode_AsUTF8(ub)) 83 | } 84 | 85 | func TestUnicodeSubstring(t *testing.T) { 86 | Py_Initialize() 87 | 88 | u := PyUnicode_FromString("aaa") 89 | assert.True(t, PyUnicode_Check(u)) 90 | assert.True(t, PyUnicode_CheckExact(u)) 91 | defer u.DecRef() 92 | 93 | sub := PyUnicode_Substring(u, 0, 2) 94 | assert.NotNil(t, sub) 95 | sub.DecRef() 96 | 97 | assert.Equal(t, "aa", PyUnicode_AsUTF8(sub)) 98 | } 99 | -------------------------------------------------------------------------------- /module.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //Module : https://docs.python.org/3/c-api/module.html#c.PyModule_Type 18 | var Module = togo((*C.PyObject)(unsafe.Pointer(&C.PyModule_Type))) 19 | 20 | //PyModule_Check : https://docs.python.org/3/c-api/module.html#c.PyModule_Check 21 | func PyModule_Check(p *PyObject) bool { 22 | return C._go_PyModule_Check(toc(p)) != 0 23 | } 24 | 25 | //PyModule_CheckExact : https://docs.python.org/3/c-api/module.html#c.PyModule_CheckExact 26 | func PyModule_CheckExact(p *PyObject) bool { 27 | return C._go_PyModule_CheckExact(toc(p)) != 0 28 | } 29 | 30 | //PyModule_NewObject : https://docs.python.org/3/c-api/module.html#c.PyModule_NewObject 31 | func PyModule_NewObject(name *PyObject) *PyObject { 32 | return togo(C.PyModule_NewObject(toc(name))) 33 | } 34 | 35 | //PyModule_New : https://docs.python.org/3/c-api/module.html#c.PyModule_New 36 | func PyModule_New(name string) *PyObject { 37 | cname := C.CString(name) 38 | defer C.free(unsafe.Pointer(cname)) 39 | 40 | return togo(C.PyModule_New(cname)) 41 | } 42 | 43 | //PyModule_GetDict : https://docs.python.org/3/c-api/module.html#c.PyModule_GetDict 44 | func PyModule_GetDict(module *PyObject) *PyObject { 45 | return togo(C.PyModule_GetDict(toc(module))) 46 | } 47 | 48 | //PyModule_GetNameObject : https://docs.python.org/3/c-api/module.html#c.PyModule_GetNameObject 49 | func PyModule_GetNameObject(module *PyObject) *PyObject { 50 | return togo(C.PyModule_GetNameObject(toc(module))) 51 | } 52 | 53 | //PyModule_GetName : https://docs.python.org/3/c-api/module.html#c.PyModule_GetName 54 | func PyModule_GetName(module *PyObject) string { 55 | cname := C.PyModule_GetName(toc(module)) 56 | return C.GoString(cname) 57 | } 58 | 59 | //PyModule_GetState : https://docs.python.org/3/c-api/module.html#c.PyModule_GetState 60 | func PyModule_GetState(module *PyObject) unsafe.Pointer { 61 | return unsafe.Pointer(C.PyModule_GetNameObject(toc(module))) 62 | } 63 | 64 | //PyModule_GetFilenameObject : https://docs.python.org/3/c-api/module.html#c.PyModule_GetFilenameObject 65 | func PyModule_GetFilenameObject(module *PyObject) *PyObject { 66 | return togo(C.PyModule_GetFilenameObject(toc(module))) 67 | } 68 | -------------------------------------------------------------------------------- /dict_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestDict(t *testing.T) { 17 | Py_Initialize() 18 | 19 | dict := PyDict_New() 20 | assert.True(t, PyDict_Check(dict)) 21 | assert.True(t, PyDict_CheckExact(dict)) 22 | defer dict.DecRef() 23 | 24 | proxy := PyDictProxy_New(dict) 25 | assert.NotNil(t, proxy) 26 | proxy.DecRef() 27 | 28 | key1 := "key1" 29 | value1 := PyUnicode_FromString("value1") 30 | assert.NotNil(t, value1) 31 | defer value1.DecRef() 32 | 33 | key2 := PyUnicode_FromString("key2") 34 | assert.NotNil(t, key2) 35 | defer key2.DecRef() 36 | value2 := PyUnicode_FromString("value2") 37 | assert.NotNil(t, value2) 38 | defer value2.DecRef() 39 | 40 | key3 := PyUnicode_FromString("key3") 41 | assert.NotNil(t, key3) 42 | defer key3.DecRef() 43 | value3 := PyUnicode_FromString("value3") 44 | assert.NotNil(t, value3) 45 | defer value3.DecRef() 46 | 47 | err := PyDict_SetItem(dict, key2, value2) 48 | assert.Zero(t, err) 49 | 50 | err = PyDict_SetItemString(dict, key1, value1) 51 | assert.Zero(t, err) 52 | 53 | assert.Equal(t, value2, PyDict_GetItem(dict, key2)) 54 | assert.Equal(t, value2, PyDict_SetDefault(dict, key2, Py_None)) 55 | assert.Equal(t, value1, PyDict_GetItemString(dict, key1)) 56 | assert.Nil(t, PyDict_GetItemWithError(dict, key3)) 57 | b := PyDict_Contains(dict, key2) != 0 58 | assert.True(t, b) 59 | 60 | assert.Equal(t, 2, PyDict_Size(dict)) 61 | 62 | keys := PyDict_Keys(dict) 63 | assert.True(t, PyList_Check(keys)) 64 | keys.DecRef() 65 | 66 | values := PyDict_Values(dict) 67 | assert.True(t, PyList_Check(values)) 68 | values.DecRef() 69 | 70 | items := PyDict_Items(dict) 71 | assert.True(t, PyList_Check(items)) 72 | items.DecRef() 73 | 74 | err = PyDict_SetItem(dict, key3, value3) 75 | assert.Zero(t, err) 76 | 77 | newDict := PyDict_Copy(dict) 78 | assert.Equal(t, 3, PyDict_Size(newDict)) 79 | defer newDict.DecRef() 80 | 81 | err = PyDict_DelItem(dict, key2) 82 | assert.Zero(t, err) 83 | 84 | err = PyDict_DelItemString(dict, key1) 85 | assert.Zero(t, err) 86 | 87 | assert.Equal(t, 1, PyDict_Size(dict)) 88 | 89 | PyDict_Clear(dict) 90 | assert.Equal(t, 0, PyDict_Size(dict)) 91 | 92 | dict.DecRef() 93 | 94 | PyDict_ClearFreeList() 95 | 96 | } 97 | -------------------------------------------------------------------------------- /sys.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | import ( 15 | "fmt" 16 | "unsafe" 17 | ) 18 | 19 | //PySys_GetObject : https://docs.python.org/3/c-api/sys.html#c.PySys_GetObject 20 | func PySys_GetObject(name string) *PyObject { 21 | cname := C.CString(name) 22 | defer C.free(unsafe.Pointer(cname)) 23 | 24 | return togo(C.PySys_GetObject(cname)) 25 | } 26 | 27 | //PySys_SetObject : https://docs.python.org/3/c-api/sys.html#c.PySys_SetObject 28 | func PySys_SetObject(name string, v *PyObject) int { 29 | cname := C.CString(name) 30 | defer C.free(unsafe.Pointer(cname)) 31 | 32 | return int(C.PySys_SetObject(cname, toc(v))) 33 | } 34 | 35 | //PySys_ResetWarnOptions : https://docs.python.org/3/c-api/sys.html#c.PySys_ResetWarnOptions 36 | func PySys_ResetWarnOptions() { 37 | C.PySys_ResetWarnOptions() 38 | } 39 | 40 | //PySys_AddWarnOption : https://docs.python.org/3/c-api/sys.html#c.PySys_AddWarnOption 41 | func PySys_AddWarnOption(s string) error { 42 | cs := C.CString(s) 43 | defer C.free(unsafe.Pointer(cs)) 44 | 45 | ws := C.Py_DecodeLocale(cs, nil) 46 | if ws == nil { 47 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", s) 48 | } 49 | defer C.PyMem_RawFree(unsafe.Pointer(ws)) 50 | 51 | C.PySys_AddWarnOption(ws) 52 | 53 | return nil 54 | } 55 | 56 | //PySys_SetPath : https://docs.python.org/3/c-api/sys.html#c.PySys_SetPath 57 | func PySys_SetPath(path string) error { 58 | cpath := C.CString(path) 59 | defer C.free(unsafe.Pointer(cpath)) 60 | 61 | wpath := C.Py_DecodeLocale(cpath, nil) 62 | if wpath == nil { 63 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", path) 64 | } 65 | defer C.PyMem_RawFree(unsafe.Pointer(wpath)) 66 | 67 | C.PySys_SetPath(wpath) 68 | 69 | return nil 70 | } 71 | 72 | //PySys_AddXOption : https://docs.python.org/3/c-api/sys.html#c.PySys_AddXOption 73 | func PySys_AddXOption(s string) error { 74 | cs := C.CString(s) 75 | defer C.free(unsafe.Pointer(cs)) 76 | 77 | ws := C.Py_DecodeLocale(cs, nil) 78 | if ws == nil { 79 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", s) 80 | } 81 | defer C.PyMem_RawFree(unsafe.Pointer(ws)) 82 | 83 | C.PySys_AddXOption(ws) 84 | 85 | return nil 86 | } 87 | 88 | //PySys_GetXOptions : https://docs.python.org/3/c-api/sys.html#c.PySys_GetXOptions 89 | func PySys_GetXOptions() *PyObject { 90 | return togo(C.PySys_GetXOptions()) 91 | } 92 | -------------------------------------------------------------------------------- /warning.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | /* 20 | All standard Python warning categories are available as global variables whose names are PyExc_ followed by the Python exception name. 21 | These have the type PyObject*; they are all class objects. 22 | */ 23 | var ( 24 | PyExc_Warning = togo(C.PyExc_Warning) 25 | PyExc_BytesWarning = togo(C.PyExc_BytesWarning) 26 | PyExc_DeprecationWarning = togo(C.PyExc_DeprecationWarning) 27 | PyExc_FutureWarning = togo(C.PyExc_FutureWarning) 28 | PyExc_ImportWarning = togo(C.PyExc_ImportWarning) 29 | PyExc_PendingDeprecationWarning = togo(C.PyExc_PendingDeprecationWarning) 30 | PyExc_ResourceWarning = togo(C.PyExc_ResourceWarning) 31 | PyExc_RuntimeWarning = togo(C.PyExc_RuntimeWarning) 32 | PyExc_SyntaxWarning = togo(C.PyExc_SyntaxWarning) 33 | PyExc_UnicodeWarning = togo(C.PyExc_UnicodeWarning) 34 | PyExc_UserWarning = togo(C.PyExc_UserWarning) 35 | ) 36 | 37 | //PyErr_WarnEx : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WarnEx 38 | func PyErr_WarnEx(category *PyObject, message string, stack_level int) int { 39 | cmessage := C.CString(message) 40 | defer C.free(unsafe.Pointer(cmessage)) 41 | 42 | return int(C.PyErr_WarnEx(toc(category), cmessage, C.Py_ssize_t(stack_level))) 43 | } 44 | 45 | //PyErr_WarnExplicitObject : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WarnExplicitObject 46 | func PyErr_WarnExplicitObject(category *PyObject, message *PyObject, filename *PyObject, lineno int, module *PyObject, registry *PyObject) int { 47 | return int(C.PyErr_WarnExplicitObject(toc(category), toc(message), toc(filename), C.int(lineno), toc(module), toc(registry))) 48 | } 49 | 50 | //PyErr_WarnExplicit : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WarnExplicit 51 | func PyErr_WarnExplicit(category *PyObject, message string, filename string, lineno int, module string, registry *PyObject) int { 52 | cmessage := C.CString(message) 53 | defer C.free(unsafe.Pointer(cmessage)) 54 | cfilename := C.CString(filename) 55 | defer C.free(unsafe.Pointer(cfilename)) 56 | cmodule := C.CString(module) 57 | defer C.free(unsafe.Pointer(cmodule)) 58 | 59 | return int(C.PyErr_WarnExplicit(toc(category), cmessage, cfilename, C.int(lineno), cmodule, toc(registry))) 60 | } 61 | -------------------------------------------------------------------------------- /module_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestModuleCheck(t *testing.T) { 11 | Py_Initialize() 12 | 13 | name := "test_module" 14 | 15 | module := PyModule_New(name) 16 | assert.True(t, PyModule_Check(module)) 17 | assert.True(t, PyModule_CheckExact(module)) 18 | defer module.DecRef() 19 | } 20 | 21 | func TestModuleNew(t *testing.T) { 22 | Py_Initialize() 23 | 24 | name := "test_module" 25 | 26 | module := PyModule_New(name) 27 | assert.NotNil(t, module) 28 | defer module.DecRef() 29 | } 30 | 31 | func TestModuleNewObject(t *testing.T) { 32 | Py_Initialize() 33 | 34 | name := "test_module" 35 | 36 | pyName := PyUnicode_FromString(name) 37 | assert.NotNil(t, pyName) 38 | defer pyName.DecRef() 39 | 40 | module := PyModule_NewObject(pyName) 41 | assert.NotNil(t, module) 42 | defer module.DecRef() 43 | } 44 | 45 | func TestModuleGetDict(t *testing.T) { 46 | Py_Initialize() 47 | 48 | name := "sys" 49 | pyName := PyUnicode_FromString(name) 50 | defer pyName.DecRef() 51 | 52 | sys := PyImport_ImportModule(name) 53 | defer sys.DecRef() 54 | 55 | dict := PyModule_GetDict(sys) 56 | assert.True(t, PyDict_Check(dict)) 57 | } 58 | 59 | func TestModuleGetName(t *testing.T) { 60 | Py_Initialize() 61 | 62 | name := "sys" 63 | pyName := PyUnicode_FromString(name) 64 | defer pyName.DecRef() 65 | 66 | sys := PyImport_ImportModule(name) 67 | defer sys.DecRef() 68 | 69 | assert.Equal(t, name, PyModule_GetName(sys)) 70 | } 71 | 72 | func TestModuleGetNameObject(t *testing.T) { 73 | Py_Initialize() 74 | 75 | name := "sys" 76 | pyName := PyUnicode_FromString(name) 77 | defer pyName.DecRef() 78 | 79 | sys := PyImport_ImportModule(name) 80 | defer sys.DecRef() 81 | 82 | assert.Equal(t, 1, pyName.RichCompareBool(PyModule_GetNameObject(sys), Py_EQ)) 83 | } 84 | 85 | func TestModuleGetState(t *testing.T) { 86 | Py_Initialize() 87 | 88 | name := "sys" 89 | pyName := PyUnicode_FromString(name) 90 | defer pyName.DecRef() 91 | 92 | sys := PyImport_ImportModule(name) 93 | defer sys.DecRef() 94 | 95 | state := PyModule_GetState(sys) 96 | assert.NotNil(t, state) 97 | } 98 | 99 | func TestModuleGetFilenameObject(t *testing.T) { 100 | Py_Initialize() 101 | 102 | name := "test" 103 | pyName := PyUnicode_FromString(name) 104 | defer pyName.DecRef() 105 | 106 | test := PyImport_ImportModule(name) 107 | defer test.DecRef() 108 | 109 | pyFilename := PyModule_GetFilenameObject(test) 110 | assert.NotNil(t, pyFilename) 111 | filename := PyUnicode_AsUTF8(pyFilename) 112 | 113 | assert.True(t, strings.Contains(filename, "/test/__init__.py")) 114 | } 115 | -------------------------------------------------------------------------------- /thread.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | //PyThreadState : https://docs.python.org/3/c-api/init.html#c.PyThreadState 16 | type PyThreadState C.PyThreadState 17 | 18 | //PyGILState is an opaque “handle” to the thread state when PyGILState_Ensure() was called, and must be passed to PyGILState_Release() to ensure Python is left in the same state 19 | type PyGILState C.PyGILState_STATE 20 | 21 | //PyEval_InitThreads : https://docs.python.org/3/c-api/init.html#c.PyEval_InitThreads 22 | func PyEval_InitThreads() { 23 | C.PyEval_InitThreads() 24 | } 25 | 26 | //PyEval_ThreadsInitialized : https://docs.python.org/3/c-api/init.html#c.PyEval_ThreadsInitialized 27 | func PyEval_ThreadsInitialized() bool { 28 | return C.PyEval_ThreadsInitialized() != 0 29 | } 30 | 31 | //PyEval_SaveThread : https://docs.python.org/3/c-api/init.html#c.PyEval_SaveThread 32 | func PyEval_SaveThread() *PyThreadState { 33 | return (*PyThreadState)(C.PyEval_SaveThread()) 34 | } 35 | 36 | //PyEval_RestoreThread : https://docs.python.org/3/c-api/init.html#c.PyEval_RestoreThread 37 | func PyEval_RestoreThread(tstate *PyThreadState) { 38 | C.PyEval_RestoreThread((*C.PyThreadState)(tstate)) 39 | } 40 | 41 | //PyThreadState_Get : https://docs.python.org/3/c-api/init.html#c.PyThreadState_Get 42 | func PyThreadState_Get() *PyThreadState { 43 | return (*PyThreadState)(C.PyThreadState_Get()) 44 | } 45 | 46 | //PyThreadState_Swap : https://docs.python.org/3/c-api/init.html#c.PyThreadState_Swap 47 | func PyThreadState_Swap(tstate *PyThreadState) *PyThreadState { 48 | return (*PyThreadState)(C.PyThreadState_Swap((*C.PyThreadState)(tstate))) 49 | } 50 | 51 | //PyEval_ReInitThreads : https://docs.python.org/3/c-api/init.html#c.PyEval_ReInitThreads 52 | func PyEval_ReInitThreads() { 53 | C.PyEval_ReInitThreads() 54 | } 55 | 56 | //PyGILState_Ensure : https://docs.python.org/3/c-api/init.html#c.PyGILState_Ensure 57 | func PyGILState_Ensure() PyGILState { 58 | return PyGILState(C.PyGILState_Ensure()) 59 | } 60 | 61 | //PyGILState_Release : https://docs.python.org/3/c-api/init.html#c.PyGILState_Release 62 | func PyGILState_Release(state PyGILState) { 63 | C.PyGILState_Release(C.PyGILState_STATE(state)) 64 | } 65 | 66 | //PyGILState_GetThisThreadState : https://docs.python.org/3/c-api/init.html#c.PyGILState_GetThisThreadState 67 | func PyGILState_GetThisThreadState() *PyThreadState { 68 | return (*PyThreadState)(C.PyGILState_GetThisThreadState()) 69 | } 70 | 71 | //PyGILState_Check : https://docs.python.org/3/c-api/init.html#c.PyGILState_Check 72 | func PyGILState_Check() bool { 73 | return C.PyGILState_Check() == 1 74 | } 75 | -------------------------------------------------------------------------------- /macro.c: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | #include "macro.h" 9 | 10 | int _go_Py_EnterRecursiveCall(const char *where) { 11 | return Py_EnterRecursiveCall(where); 12 | } 13 | 14 | void _go_Py_LeaveRecursiveCall() { 15 | Py_LeaveRecursiveCall(); 16 | } 17 | 18 | int _go_PyType_Check(PyObject *o) { 19 | return PyType_Check(o); 20 | } 21 | int _go_PyType_CheckExact(PyObject *o) { 22 | return PyType_CheckExact(o); 23 | } 24 | 25 | 26 | 27 | int _go_PyLong_Check(PyObject *p) { 28 | return PyLong_Check(p); 29 | } 30 | int _go_PyLong_CheckExact(PyObject *p) { 31 | return PyLong_CheckExact(p); 32 | } 33 | 34 | int _go_PyBool_Check(PyObject *o) { 35 | return PyBool_Check(o); 36 | } 37 | 38 | int _go_PyFloat_Check(PyObject *p) { 39 | return PyFloat_Check(p); 40 | } 41 | 42 | int _go_PyFloat_CheckExact(PyObject *p) { 43 | return PyFloat_CheckExact(p); 44 | } 45 | 46 | int _go_PyComplex_Check(PyObject *p) { 47 | return PyComplex_Check(p); 48 | } 49 | 50 | int _go_PyComplex_CheckExact(PyObject *p) { 51 | return PyComplex_CheckExact(p); 52 | } 53 | 54 | int _go_PyBytes_Check(PyObject *o) { 55 | return PyBytes_Check(o); 56 | } 57 | int _go_PyBytes_CheckExact(PyObject *o) { 58 | return PyBytes_CheckExact(o); 59 | } 60 | 61 | int _go_PyByteArray_Check(PyObject *o) { 62 | return PyByteArray_Check(o); 63 | } 64 | int _go_PyByteArray_CheckExact(PyObject *o) { 65 | return PyByteArray_CheckExact(o); 66 | } 67 | 68 | int _go_PyUnicode_Check(PyObject *o) { 69 | return PyUnicode_Check(o); 70 | } 71 | int _go_PyUnicode_CheckExact(PyObject *o) { 72 | return PyUnicode_CheckExact(o); 73 | } 74 | 75 | int _go_PyTuple_Check(PyObject *p) { 76 | return PyTuple_Check(p); 77 | } 78 | int _go_PyTuple_CheckExact(PyObject *p) { 79 | return PyTuple_CheckExact(p); 80 | } 81 | 82 | int _go_PyList_Check(PyObject *p) { 83 | return PyList_Check(p); 84 | } 85 | int _go_PyList_CheckExact(PyObject *p) { 86 | return PyList_CheckExact(p); 87 | } 88 | 89 | int _go_PyDict_Check(PyObject *p) { 90 | return PyDict_Check(p); 91 | } 92 | int _go_PyDict_CheckExact(PyObject *p) { 93 | return PyDict_CheckExact(p); 94 | } 95 | 96 | int _go_PyModule_Check(PyObject *p) { 97 | return PyModule_Check(p); 98 | } 99 | int _go_PyModule_CheckExact(PyObject *p) { 100 | return PyModule_CheckExact(p); 101 | } 102 | 103 | int _go_PyObject_DelAttr(PyObject *o, PyObject *attr_name) { 104 | return PyObject_DelAttr(o, attr_name); 105 | } 106 | int _go_PyObject_DelAttrString(PyObject *o, const char *attr_name) { 107 | return PyObject_DelAttrString(o, attr_name); 108 | } 109 | 110 | int _go_PyObject_TypeCheck(PyObject *o, PyTypeObject *type) { 111 | return PyObject_TypeCheck(o, type); 112 | } -------------------------------------------------------------------------------- /list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import "unsafe" 16 | 17 | //List : https://docs.python.org/3/c-api/list.html#c.PyList_Type 18 | var List = togo((*C.PyObject)(unsafe.Pointer(&C.PyList_Type))) 19 | 20 | //PyList_Check : https://docs.python.org/3/c-api/list.html#c.PyList_Check 21 | func PyList_Check(p *PyObject) bool { 22 | return C._go_PyList_Check(toc(p)) != 0 23 | } 24 | 25 | //PyList_CheckExact : https://docs.python.org/3/c-api/list.html#c.PyList_CheckExact 26 | func PyList_CheckExact(p *PyObject) bool { 27 | return C._go_PyList_CheckExact(toc(p)) != 0 28 | } 29 | 30 | //PyList_New : https://docs.python.org/3/c-api/list.html#c.PyList_New 31 | func PyList_New(len int) *PyObject { 32 | return togo(C.PyList_New(C.Py_ssize_t(len))) 33 | } 34 | 35 | //PyList_Size : https://docs.python.org/3/c-api/list.html#c.PyList_Size 36 | func PyList_Size(p *PyObject) int { 37 | return int(C.PyList_Size(toc(p))) 38 | } 39 | 40 | //PyList_GetItem : https://docs.python.org/3/c-api/list.html#c.PyList_GetItem 41 | func PyList_GetItem(p *PyObject, pos int) *PyObject { 42 | return togo(C.PyList_GetItem(toc(p), C.Py_ssize_t(pos))) 43 | } 44 | 45 | //PyList_SetItem : https://docs.python.org/3/c-api/list.html#c.PyList_SetItem 46 | func PyList_SetItem(p *PyObject, pos int, o *PyObject) int { 47 | return int(C.PyList_SetItem(toc(p), C.Py_ssize_t(pos), toc(o))) 48 | } 49 | 50 | //PyList_Insert : https://docs.python.org/3/c-api/list.html#c.PyList_Insert 51 | func PyList_Insert(p *PyObject, index int, item *PyObject) int { 52 | return int(C.PyList_Insert(toc(p), C.Py_ssize_t(index), toc(item))) 53 | } 54 | 55 | //PyList_Append : https://docs.python.org/3/c-api/list.html#c.PyList_Append 56 | func PyList_Append(p, item *PyObject) int { 57 | return int(C.PyList_Append(toc(p), toc(item))) 58 | } 59 | 60 | //PyList_GetSlice : https://docs.python.org/3/c-api/list.html#c.PyList_GetSlice 61 | func PyList_GetSlice(p *PyObject, low, high int) *PyObject { 62 | return togo(C.PyList_GetSlice(toc(p), C.Py_ssize_t(low), C.Py_ssize_t(high))) 63 | } 64 | 65 | //PyList_SetSlice : https://docs.python.org/3/c-api/list.html#c.PyList_SetSlice 66 | func PyList_SetSlice(p *PyObject, low, high int, itemlist *PyObject) int { 67 | return int(C.PyList_SetSlice(toc(p), C.Py_ssize_t(low), C.Py_ssize_t(high), toc(itemlist))) 68 | } 69 | 70 | //PyList_Sort : https://docs.python.org/3/c-api/list.html#c.PyList_Sort 71 | func PyList_Sort(list *PyObject) int { 72 | return int(C.PyList_Sort(toc(list))) 73 | } 74 | 75 | //PyList_Reverse : https://docs.python.org/3/c-api/list.html#c.PyList_Reverse 76 | func PyList_Reverse(list *PyObject) int { 77 | return int(C.PyList_Reverse(toc(list))) 78 | } 79 | 80 | //PyList_AsTuple : https://docs.python.org/3/c-api/list.html#c.PyList_AsTuple 81 | func PyList_AsTuple(list *PyObject) *PyObject { 82 | return togo(C.PyList_AsTuple(toc(list))) 83 | } 84 | 85 | //PyList_ClearFreeList : https://docs.python.org/3/c-api/list.html#c.PyList_ClearFreeList 86 | func PyList_ClearFreeList() int { 87 | return int(C.PyList_ClearFreeList()) 88 | } 89 | -------------------------------------------------------------------------------- /lifecycle_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestInitialization(t *testing.T) { 17 | 18 | Py_Initialize() 19 | assert.True(t, Py_IsInitialized()) 20 | Py_Finalize() 21 | assert.False(t, Py_IsInitialized()) 22 | 23 | } 24 | 25 | func TestInitializationEx(t *testing.T) { 26 | 27 | Py_Initialize() 28 | assert.True(t, Py_IsInitialized()) 29 | assert.Zero(t, Py_FinalizeEx()) 30 | assert.False(t, Py_IsInitialized()) 31 | 32 | } 33 | 34 | func TestProgramName(t *testing.T) { 35 | Py_Finalize() 36 | 37 | defaultName, err := Py_GetProgramName() 38 | defer Py_SetProgramName(defaultName) 39 | 40 | assert.Nil(t, err) 41 | name := "py3é" 42 | Py_SetProgramName(name) 43 | newName, err := Py_GetProgramName() 44 | assert.Nil(t, err) 45 | assert.Equal(t, name, newName) 46 | 47 | } 48 | 49 | func TestPrefix(t *testing.T) { 50 | prefix, err := Py_GetPrefix() 51 | assert.Nil(t, err) 52 | assert.IsType(t, "", prefix) 53 | 54 | } 55 | 56 | func TestExecPrefix(t *testing.T) { 57 | execPrefix, err := Py_GetExecPrefix() 58 | assert.Nil(t, err) 59 | assert.IsType(t, "", execPrefix) 60 | 61 | } 62 | 63 | func TestProgramFullPath(t *testing.T) { 64 | programFullPath, err := Py_GetProgramFullPath() 65 | assert.Nil(t, err) 66 | assert.IsType(t, "", programFullPath) 67 | 68 | } 69 | 70 | func TestPath(t *testing.T) { 71 | Py_Finalize() 72 | 73 | defaultPath, err := Py_GetPath() 74 | defer Py_SetPath(defaultPath) 75 | 76 | assert.Nil(t, err) 77 | name := "påth" 78 | Py_SetPath(name) 79 | newName, err := Py_GetPath() 80 | assert.Nil(t, err) 81 | assert.Equal(t, name, newName) 82 | 83 | } 84 | 85 | func TestVersion(t *testing.T) { 86 | version := Py_GetVersion() 87 | assert.IsType(t, "", version) 88 | } 89 | 90 | func TestPlatform(t *testing.T) { 91 | platform := Py_GetPlatform() 92 | assert.IsType(t, "", platform) 93 | } 94 | 95 | func TestCopyright(t *testing.T) { 96 | copyright := Py_GetCopyright() 97 | assert.IsType(t, "", copyright) 98 | } 99 | 100 | func TestCompiler(t *testing.T) { 101 | compiler := Py_GetCompiler() 102 | assert.IsType(t, "", compiler) 103 | } 104 | 105 | func TestBuildInfo(t *testing.T) { 106 | buildInfo := Py_GetBuildInfo() 107 | assert.IsType(t, "", buildInfo) 108 | } 109 | 110 | func TestPythonHome(t *testing.T) { 111 | name := "høme" 112 | 113 | defaultHome, err := Py_GetPythonHome() 114 | defer Py_SetPythonHome(defaultHome) 115 | 116 | assert.Nil(t, err) 117 | Py_SetPythonHome(name) 118 | newName, err := Py_GetPythonHome() 119 | assert.Nil(t, err) 120 | assert.Equal(t, name, newName) 121 | } 122 | 123 | func TestSetArgv(t *testing.T) { 124 | Py_Initialize() 125 | 126 | PySys_SetArgv([]string{"test.py"}) 127 | 128 | argv := PySys_GetObject("argv") 129 | assert.Equal(t, 1, PyList_Size(argv)) 130 | assert.Equal(t, "test.py", PyUnicode_AsUTF8(PyList_GetItem(argv, 0))) 131 | 132 | Py_Finalize() 133 | } 134 | 135 | func TestSetArgvEx(t *testing.T) { 136 | Py_Initialize() 137 | 138 | PySys_SetArgvEx([]string{"test.py"}, false) 139 | 140 | argv := PySys_GetObject("argv") 141 | assert.Equal(t, 1, PyList_Size(argv)) 142 | assert.Equal(t, "test.py", PyUnicode_AsUTF8(PyList_GetItem(argv, 0))) 143 | 144 | Py_Finalize() 145 | } 146 | -------------------------------------------------------------------------------- /unicode.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | //Unicode : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_Type 20 | var Unicode = togo((*C.PyObject)(unsafe.Pointer(&C.PyUnicode_Type))) 21 | 22 | //PyUnicode_Check : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_Check 23 | func PyUnicode_Check(o *PyObject) bool { 24 | return C._go_PyUnicode_Check(toc(o)) != 0 25 | } 26 | 27 | //PyUnicode_CheckExact : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_CheckExact 28 | func PyUnicode_CheckExact(o *PyObject) bool { 29 | return C._go_PyUnicode_CheckExact(toc(o)) != 0 30 | } 31 | 32 | //PyUnicode_New : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_New 33 | func PyUnicode_New(size int, maxchar rune) *PyObject { 34 | return togo(C.PyUnicode_New(C.Py_ssize_t(size), C.Py_UCS4(maxchar))) 35 | } 36 | 37 | //PyUnicode_FromString : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_FromString 38 | func PyUnicode_FromString(u string) *PyObject { 39 | cu := C.CString(u) 40 | defer C.free(unsafe.Pointer(cu)) 41 | 42 | return togo(C.PyUnicode_FromString(cu)) 43 | } 44 | 45 | //PyUnicode_FromEncodedObject : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_FromEncodedObject 46 | func PyUnicode_FromEncodedObject(obj *PyObject, encoding, errors string) *PyObject { 47 | cencoding := C.CString(encoding) 48 | defer C.free(unsafe.Pointer(cencoding)) 49 | 50 | cerrors := C.CString(errors) 51 | defer C.free(unsafe.Pointer(cerrors)) 52 | 53 | return togo(C.PyUnicode_FromEncodedObject(toc(obj), cencoding, cerrors)) 54 | } 55 | 56 | //PyUnicode_GetLength : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_GetLength 57 | func PyUnicode_GetLength(unicode *PyObject) int { 58 | return int(C.PyUnicode_GetLength(toc(unicode))) 59 | } 60 | 61 | //PyUnicode_CopyCharacters : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_CopyCharacters 62 | func PyUnicode_CopyCharacters(to, from *PyObject, to_start, from_start, how_many int) int { 63 | return int(C.PyUnicode_CopyCharacters(toc(to), C.Py_ssize_t(to_start), toc(from), C.Py_ssize_t(from_start), C.Py_ssize_t(how_many))) 64 | 65 | } 66 | 67 | //PyUnicode_Fill : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_Fill 68 | func PyUnicode_Fill(unicode *PyObject, start, length int, fill_char rune) int { 69 | return int(C.PyUnicode_Fill(toc(unicode), C.Py_ssize_t(start), C.Py_ssize_t(length), C.Py_UCS4(fill_char))) 70 | } 71 | 72 | //PyUnicode_WriteChar : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_WriteChar 73 | func PyUnicode_WriteChar(unicode *PyObject, index int, character rune) int { 74 | return int(C.PyUnicode_WriteChar(toc(unicode), C.Py_ssize_t(index), C.Py_UCS4(character))) 75 | } 76 | 77 | //PyUnicode_ReadChar : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_ReadChar 78 | func PyUnicode_ReadChar(unicode *PyObject, index int) rune { 79 | return rune(C.PyUnicode_ReadChar(toc(unicode), C.Py_ssize_t(index))) 80 | } 81 | 82 | //PyUnicode_Substring : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_Substring 83 | func PyUnicode_Substring(unicode *PyObject, start, end int) *PyObject { 84 | return togo(C.PyUnicode_Substring(toc(unicode), C.Py_ssize_t(start), C.Py_ssize_t(end))) 85 | } 86 | 87 | //PyUnicode_AsUTF8 : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_AsUTF8 88 | func PyUnicode_AsUTF8(unicode *PyObject) string { 89 | cutf8 := C.PyUnicode_AsUTF8(toc(unicode)) 90 | return C.GoString(cutf8) 91 | } 92 | -------------------------------------------------------------------------------- /integer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "strconv" 12 | "testing" 13 | 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestPyLongCheck(t *testing.T) { 18 | Py_Initialize() 19 | 20 | pyLong := PyLong_FromGoInt(345) 21 | assert.True(t, PyLong_Check(pyLong)) 22 | assert.True(t, PyLong_CheckExact(pyLong)) 23 | pyLong.DecRef() 24 | } 25 | 26 | func TestPyLongFromAsLong(t *testing.T) { 27 | Py_Initialize() 28 | v := 2354 29 | pyLong := PyLong_FromLong(v) 30 | assert.NotNil(t, pyLong) 31 | assert.Equal(t, v, PyLong_AsLong(pyLong)) 32 | pyLong.DecRef() 33 | } 34 | 35 | func TestPyLongFromAsUnsignedLong(t *testing.T) { 36 | Py_Initialize() 37 | v := uint(2354) 38 | pyLong := PyLong_FromUnsignedLong(v) 39 | assert.NotNil(t, pyLong) 40 | assert.Equal(t, v, PyLong_AsUnsignedLong(pyLong)) 41 | pyLong.DecRef() 42 | } 43 | 44 | func TestPyLongFromAsLongLong(t *testing.T) { 45 | Py_Initialize() 46 | v := int64(2354) 47 | pyLong := PyLong_FromLongLong(v) 48 | assert.NotNil(t, pyLong) 49 | assert.Equal(t, v, PyLong_AsLongLong(pyLong)) 50 | pyLong.DecRef() 51 | } 52 | 53 | func TestPyLongFromAsUnsignedLongLong(t *testing.T) { 54 | Py_Initialize() 55 | v := uint64(2354) 56 | pyLong := PyLong_FromUnsignedLongLong(v) 57 | assert.NotNil(t, pyLong) 58 | assert.Equal(t, v, PyLong_AsUnsignedLongLong(pyLong)) 59 | pyLong.DecRef() 60 | } 61 | 62 | func TestPyLongFromAsDouble(t *testing.T) { 63 | Py_Initialize() 64 | v := float64(2354.0) 65 | pyLong := PyLong_FromDouble(v) 66 | assert.NotNil(t, pyLong) 67 | assert.Equal(t, v, PyLong_AsDouble(pyLong)) 68 | pyLong.DecRef() 69 | } 70 | 71 | func TestPyLongFromAsGoFloat64(t *testing.T) { 72 | Py_Initialize() 73 | v := float64(2354.0) 74 | pyLong := PyLong_FromGoFloat64(v) 75 | assert.NotNil(t, pyLong) 76 | assert.Equal(t, v, PyLong_AsDouble(pyLong)) 77 | pyLong.DecRef() 78 | } 79 | 80 | func TestPyLongFromAsString(t *testing.T) { 81 | Py_Initialize() 82 | v := 2354 83 | s := strconv.Itoa(v) 84 | pyLong := PyLong_FromString(s, 10) 85 | assert.NotNil(t, pyLong) 86 | assert.Equal(t, v, PyLong_AsLong(pyLong)) 87 | pyLong.DecRef() 88 | } 89 | 90 | func TestPyLongFromAsUnicodeObject(t *testing.T) { 91 | Py_Initialize() 92 | v := 2354 93 | s := strconv.Itoa(v) 94 | pyUnicode := PyUnicode_FromString(s) 95 | assert.NotNil(t, pyUnicode) 96 | pyLong := PyLong_FromUnicodeObject(pyUnicode, 10) 97 | assert.NotNil(t, pyLong) 98 | assert.Equal(t, v, PyLong_AsLong(pyLong)) 99 | pyLong.DecRef() 100 | pyUnicode.DecRef() 101 | } 102 | 103 | func TestPyLongFromAsGoInt(t *testing.T) { 104 | Py_Initialize() 105 | v := 2354 106 | pyLong := PyLong_FromGoInt(v) 107 | assert.NotNil(t, pyLong) 108 | assert.Equal(t, v, PyLong_AsLong(pyLong)) 109 | pyLong.DecRef() 110 | } 111 | 112 | func TestPyLongFromAsGoUint(t *testing.T) { 113 | Py_Initialize() 114 | v := uint(2354) 115 | pyLong := PyLong_FromGoUint(v) 116 | assert.NotNil(t, pyLong) 117 | assert.Equal(t, v, PyLong_AsUnsignedLong(pyLong)) 118 | pyLong.DecRef() 119 | } 120 | 121 | func TestPyLongFromAsGoInt64(t *testing.T) { 122 | Py_Initialize() 123 | v := int64(2354) 124 | pyLong := PyLong_FromGoInt64(v) 125 | assert.NotNil(t, pyLong) 126 | assert.Equal(t, v, PyLong_AsLongLong(pyLong)) 127 | pyLong.DecRef() 128 | } 129 | 130 | func TestPyLongFromAsGoUint64(t *testing.T) { 131 | Py_Initialize() 132 | v := uint64(2354) 133 | pyLong := PyLong_FromGoUint64(v) 134 | assert.NotNil(t, pyLong) 135 | assert.Equal(t, v, PyLong_AsUnsignedLongLong(pyLong)) 136 | pyLong.DecRef() 137 | } 138 | -------------------------------------------------------------------------------- /dict.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | //Dict : https://docs.python.org/3/c-api/dict.html#c.PyDict_Type 20 | var Dict = togo((*C.PyObject)(unsafe.Pointer(&C.PyDict_Type))) 21 | 22 | //PyDict_Check : https://docs.python.org/3/c-api/dict.html#c.PyDict_Check 23 | func PyDict_Check(p *PyObject) bool { 24 | return C._go_PyDict_Check(toc(p)) != 0 25 | } 26 | 27 | //PyDict_CheckExact : https://docs.python.org/3/c-api/dict.html#c.PyDict_CheckExact 28 | func PyDict_CheckExact(p *PyObject) bool { 29 | return C._go_PyDict_CheckExact(toc(p)) != 0 30 | } 31 | 32 | //PyDict_New : https://docs.python.org/3/c-api/dict.html#c.PyDict_New 33 | func PyDict_New() *PyObject { 34 | return togo(C.PyDict_New()) 35 | } 36 | 37 | //PyDictProxy_New : https://docs.python.org/3/c-api/dict.html#c.PyDictProxy_New 38 | func PyDictProxy_New(mapping *PyObject) *PyObject { 39 | return togo(C.PyDictProxy_New(toc(mapping))) 40 | } 41 | 42 | //PyDict_Clear : https://docs.python.org/3/c-api/dict.html#c.PyDict_Clear 43 | func PyDict_Clear(p *PyObject) { 44 | C.PyDict_Clear(toc(p)) 45 | } 46 | 47 | //PyDict_Contains : https://docs.python.org/3/c-api/dict.html#c.PyDict_Contains 48 | func PyDict_Contains(p, key *PyObject) int { 49 | return int(C.PyDict_Contains(toc(p), toc(key))) 50 | } 51 | 52 | //PyDict_Copy : https://docs.python.org/3/c-api/dict.html#c.PyDict_Copy 53 | func PyDict_Copy(p *PyObject) *PyObject { 54 | return togo(C.PyDict_Copy(toc(p))) 55 | } 56 | 57 | //PyDict_SetItem : https://docs.python.org/3/c-api/dict.html#c.PyDict_SetItem 58 | func PyDict_SetItem(p, key, val *PyObject) int { 59 | return int(C.PyDict_SetItem(toc(p), toc(key), toc(val))) 60 | } 61 | 62 | //PyDict_SetItemString : https://docs.python.org/3/c-api/dict.html#c.PyDict_SetItemString 63 | func PyDict_SetItemString(p *PyObject, key string, val *PyObject) int { 64 | ckey := C.CString(key) 65 | defer C.free(unsafe.Pointer(ckey)) 66 | return int(C.PyDict_SetItemString(toc(p), ckey, toc(val))) 67 | } 68 | 69 | //PyDict_DelItem : https://docs.python.org/3/c-api/dict.html#c.PyDict_DelItem 70 | func PyDict_DelItem(p, key *PyObject) int { 71 | return int(C.PyDict_DelItem(toc(p), toc(key))) 72 | } 73 | 74 | //PyDict_DelItemString : https://docs.python.org/3/c-api/dict.html#c.PyDict_DelItemString 75 | func PyDict_DelItemString(p *PyObject, key string) int { 76 | ckey := C.CString(key) 77 | defer C.free(unsafe.Pointer(ckey)) 78 | return int(C.PyDict_DelItemString(toc(p), ckey)) 79 | } 80 | 81 | //PyDict_GetItem : https://docs.python.org/3/c-api/dict.html#c.PyDict_GetItem 82 | func PyDict_GetItem(p, key *PyObject) *PyObject { 83 | return togo(C.PyDict_GetItem(toc(p), toc(key))) 84 | } 85 | 86 | //PyDict_GetItemWithError : https://docs.python.org/3/c-api/dict.html#c.PyDict_GetItemWithError 87 | func PyDict_GetItemWithError(p, key *PyObject) *PyObject { 88 | return togo(C.PyDict_GetItemWithError(toc(p), toc(key))) 89 | } 90 | 91 | //PyDict_GetItemString : https://docs.python.org/3/c-api/dict.html#c.PyDict_GetItemString 92 | func PyDict_GetItemString(p *PyObject, key string) *PyObject { 93 | ckey := C.CString(key) 94 | defer C.free(unsafe.Pointer(ckey)) 95 | 96 | return togo(C.PyDict_GetItemString(toc(p), ckey)) 97 | } 98 | 99 | //PyDict_SetDefault : https://docs.python.org/3/c-api/dict.html#c.PyDict_SetDefault 100 | func PyDict_SetDefault(p, key, pyDefault *PyObject) *PyObject { 101 | return togo(C.PyDict_SetDefault(toc(p), toc(key), toc(pyDefault))) 102 | } 103 | 104 | //PyDict_Items : https://docs.python.org/3/c-api/dict.html#c.PyDict_Items 105 | func PyDict_Items(p *PyObject) *PyObject { 106 | return togo(C.PyDict_Items(toc(p))) 107 | } 108 | 109 | //PyDict_Keys : https://docs.python.org/3/c-api/dict.html#c.PyDict_Keys 110 | func PyDict_Keys(p *PyObject) *PyObject { 111 | return togo(C.PyDict_Keys(toc(p))) 112 | } 113 | 114 | //PyDict_Values : https://docs.python.org/3/c-api/dict.html#c.PyDict_Values 115 | func PyDict_Values(p *PyObject) *PyObject { 116 | return togo(C.PyDict_Values(toc(p))) 117 | } 118 | 119 | //PyDict_Size : https://docs.python.org/3/c-api/dict.html#c.PyDict_Size 120 | func PyDict_Size(p *PyObject) int { 121 | return int(C.PyDict_Size(toc(p))) 122 | } 123 | 124 | //PyDict_Next : https://docs.python.org/3/c-api/dict.html#c.PyDict_Next 125 | func PyDict_Next(p *PyObject, ppos *int, pkey, pvalue **PyObject) bool { 126 | cpos := C.Py_ssize_t(*ppos) 127 | ckey := toc(*pkey) 128 | cvalue := toc(*pvalue) 129 | 130 | res := C.PyDict_Next(toc(p), &cpos, &ckey, &cvalue) != 0 131 | 132 | *ppos = int(cpos) 133 | *pkey = togo(ckey) 134 | *pvalue = togo(cvalue) 135 | 136 | return res 137 | } 138 | 139 | //PyDict_ClearFreeList : https://docs.python.org/3/c-api/dict.html#c.PyDict_ClearFreeList 140 | func PyDict_ClearFreeList() int { 141 | return int(C.PyDict_ClearFreeList()) 142 | } 143 | -------------------------------------------------------------------------------- /integer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | #include "macro.h" 13 | */ 14 | import "C" 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | //Long : https://docs.python.org/3/c-api/long.html#c.PyLong_Type 20 | var Long = togo((*C.PyObject)(unsafe.Pointer(&C.PyLong_Type))) 21 | 22 | //PyLong_Check : https://docs.python.org/3/c-api/long.html#c.PyLong_Check 23 | func PyLong_Check(p *PyObject) bool { 24 | return C._go_PyLong_Check(toc(p)) != 0 25 | } 26 | 27 | //PyLong_CheckExact : https://docs.python.org/3/c-api/long.html#c.PyLong_CheckExact 28 | func PyLong_CheckExact(p *PyObject) bool { 29 | return C._go_PyLong_CheckExact(toc(p)) != 0 30 | } 31 | 32 | //PyLong_FromLong : https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong 33 | func PyLong_FromLong(v int) *PyObject { 34 | return togo(C.PyLong_FromLong(C.long(v))) 35 | } 36 | 37 | //PyLong_FromUnsignedLong : https://docs.python.org/3/c-api/long.html#c.PyLong_FromUnsignedLong 38 | func PyLong_FromUnsignedLong(v uint) *PyObject { 39 | return togo(C.PyLong_FromUnsignedLong(C.ulong(v))) 40 | } 41 | 42 | //PyLong_FromLongLong : https://docs.python.org/3/c-api/long.html#c.PyLong_FromLongLong 43 | func PyLong_FromLongLong(v int64) *PyObject { 44 | return togo(C.PyLong_FromLongLong(C.longlong(v))) 45 | } 46 | 47 | //PyLong_FromUnsignedLongLong : https://docs.python.org/3/c-api/long.html#c.PyLong_FromUnsignedLongLong 48 | func PyLong_FromUnsignedLongLong(v uint64) *PyObject { 49 | return togo(C.PyLong_FromUnsignedLongLong(C.ulonglong(v))) 50 | } 51 | 52 | //PyLong_FromDouble : https://docs.python.org/3/c-api/long.html#c.PyLong_FromDouble 53 | func PyLong_FromDouble(v float64) *PyObject { 54 | return togo(C.PyLong_FromDouble(C.double(v))) 55 | } 56 | 57 | //PyLong_FromString : https://docs.python.org/3/c-api/long.html#c.PyLong_FromString 58 | func PyLong_FromString(str string, base int) *PyObject { 59 | cstr := C.CString(str) 60 | defer C.free(unsafe.Pointer(cstr)) 61 | 62 | return togo(C.PyLong_FromString(cstr, nil, C.int(base))) 63 | } 64 | 65 | //PyLong_FromUnicodeObject : https://docs.python.org/3/c-api/long.html#c.PyLong_FromUnicodeObject 66 | func PyLong_FromUnicodeObject(u *PyObject, base int) *PyObject { 67 | return togo(C.PyLong_FromUnicodeObject(toc(u), C.int(base))) 68 | } 69 | 70 | //PyLong_FromGoInt ensures the go integer type does not overflow 71 | func PyLong_FromGoInt(v int) *PyObject { 72 | return togo(C.PyLong_FromLongLong(C.longlong(v))) 73 | } 74 | 75 | //PyLong_FromGoUint ensures the go integer type does not overflow 76 | func PyLong_FromGoUint(v uint) *PyObject { 77 | return togo(C.PyLong_FromUnsignedLongLong(C.ulonglong(v))) 78 | } 79 | 80 | //PyLong_FromGoInt64 ensures the go integer type does not overflow 81 | func PyLong_FromGoInt64(v int64) *PyObject { 82 | return togo(C.PyLong_FromLongLong(C.longlong(v))) 83 | } 84 | 85 | //PyLong_FromGoUint64 ensures the go integer type does not overflow 86 | func PyLong_FromGoUint64(v uint64) *PyObject { 87 | return togo(C.PyLong_FromUnsignedLongLong(C.ulonglong(v))) 88 | } 89 | 90 | //PyLong_FromGoFloat64 ensures the go integer type does not overflow 91 | func PyLong_FromGoFloat64(v float64) *PyObject { 92 | return togo(C.PyLong_FromDouble(C.double(v))) 93 | } 94 | 95 | //PyLong_AsLong : https://docs.python.org/3/c-api/long.html#c.PyLong_AsLong 96 | func PyLong_AsLong(obj *PyObject) int { 97 | return int(C.PyLong_AsLong(toc(obj))) 98 | } 99 | 100 | //PyLong_AsLongAndOverflow : https://docs.python.org/3/c-api/long.html#c.PyLong_AsLongAndOverflow 101 | func PyLong_AsLongAndOverflow(obj *PyObject) (int, int) { 102 | overflow := C.int(0) 103 | ret := C.PyLong_AsLongAndOverflow(toc(obj), &overflow) 104 | return int(ret), int(overflow) 105 | } 106 | 107 | //PyLong_AsLongLong : https://docs.python.org/3/c-api/long.html#c.PyLong_AsLongLong 108 | func PyLong_AsLongLong(obj *PyObject) int64 { 109 | return int64(C.PyLong_AsLongLong(toc(obj))) 110 | } 111 | 112 | //PyLong_AsLongLongAndOverflow : https://docs.python.org/3/c-api/long.html#c.PyLong_AsLongLongAndOverflow 113 | func PyLong_AsLongLongAndOverflow(obj *PyObject) (int64, int) { 114 | overflow := C.int(0) 115 | ret := C.PyLong_AsLongLongAndOverflow(toc(obj), &overflow) 116 | return int64(ret), int(overflow) 117 | } 118 | 119 | //PyLong_AsUnsignedLong : https://docs.python.org/3/c-api/long.html#c.PyLong_AsUnsignedLong 120 | func PyLong_AsUnsignedLong(obj *PyObject) uint { 121 | return uint(C.PyLong_AsUnsignedLong(toc(obj))) 122 | } 123 | 124 | //PyLong_AsUnsignedLongLong : https://docs.python.org/3/c-api/long.html#c.PyLong_AsUnsignedLongLong 125 | func PyLong_AsUnsignedLongLong(obj *PyObject) uint64 { 126 | return uint64(C.PyLong_AsUnsignedLongLong(toc(obj))) 127 | } 128 | 129 | //PyLong_AsUnsignedLongMask : https://docs.python.org/3/c-api/long.html#c.PyLong_AsUnsignedLongMask 130 | func PyLong_AsUnsignedLongMask(obj *PyObject) uint { 131 | return uint(C.PyLong_AsUnsignedLongMask(toc(obj))) 132 | } 133 | 134 | //PyLong_AsUnsignedLongLongMask : https://docs.python.org/3/c-api/long.html#c.PyLong_AsUnsignedLongLongMask 135 | func PyLong_AsUnsignedLongLongMask(obj *PyObject) uint64 { 136 | return uint64(C.PyLong_AsUnsignedLongLongMask(toc(obj))) 137 | } 138 | 139 | //PyLong_AsDouble : https://docs.python.org/3/c-api/long.html#c.PyLong_AsDouble 140 | func PyLong_AsDouble(obj *PyObject) float64 { 141 | return float64(C.PyLong_AsDouble(toc(obj))) 142 | } 143 | -------------------------------------------------------------------------------- /import.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | //PyImport_ImportModule : https://docs.python.org/3/c-api/import.html#c.PyImport_ImportModule 20 | func PyImport_ImportModule(name string) *PyObject { 21 | cname := C.CString(name) 22 | defer C.free(unsafe.Pointer(cname)) 23 | 24 | return togo(C.PyImport_ImportModule(cname)) 25 | } 26 | 27 | //PyImport_ImportModuleEx : https://docs.python.org/3/c-api/import.html#c.PyImport_ImportModuleEx 28 | func PyImport_ImportModuleEx(name string, globals, locals, fromlist *PyObject) *PyObject { 29 | return PyImport_ImportModuleLevel(name, globals, locals, fromlist, 0) 30 | } 31 | 32 | //PyImport_ImportModuleLevelObject : https://docs.python.org/3/c-api/import.html#c.PyImport_ImportModuleLevelObject 33 | func PyImport_ImportModuleLevelObject(name, globals, locals, fromlist *PyObject, level int) *PyObject { 34 | return togo(C.PyImport_ImportModuleLevelObject(toc(name), toc(globals), toc(locals), toc(fromlist), C.int(level))) 35 | } 36 | 37 | //PyImport_ImportModuleLevel : https://docs.python.org/3/c-api/import.html#c.PyImport_ImportModuleLevel 38 | func PyImport_ImportModuleLevel(name string, globals, locals, fromlist *PyObject, level int) *PyObject { 39 | cname := C.CString(name) 40 | defer C.free(unsafe.Pointer(cname)) 41 | 42 | return togo(C.PyImport_ImportModuleLevel(cname, toc(globals), toc(locals), toc(fromlist), C.int(level))) 43 | } 44 | 45 | //PyImport_Import : https://docs.python.org/3/c-api/import.html#c.PyImport_Import 46 | func PyImport_Import(name *PyObject) *PyObject { 47 | return togo(C.PyImport_Import(toc(name))) 48 | } 49 | 50 | //PyImport_ReloadModule : https://docs.python.org/3/c-api/import.html#c.PyImport_ReloadModule 51 | func PyImport_ReloadModule(name *PyObject) *PyObject { 52 | return togo(C.PyImport_ReloadModule(toc(name))) 53 | } 54 | 55 | //PyImport_AddModuleObject : https://docs.python.org/3/c-api/import.html#c.PyImport_AddModuleObject 56 | func PyImport_AddModuleObject(name *PyObject) *PyObject { 57 | return togo(C.PyImport_AddModuleObject(toc(name))) 58 | } 59 | 60 | //PyImport_AddModule : https://docs.python.org/3/c-api/import.html#c.PyImport_AddModule 61 | func PyImport_AddModule(name string) *PyObject { 62 | cname := C.CString(name) 63 | defer C.free(unsafe.Pointer(cname)) 64 | 65 | return togo(C.PyImport_AddModule(cname)) 66 | } 67 | 68 | //PyImport_ExecCodeModule : https://docs.python.org/3/c-api/import.html#c.PyImport_ExecCodeModule 69 | func PyImport_ExecCodeModule(name string, co *PyObject) *PyObject { 70 | cname := C.CString(name) 71 | defer C.free(unsafe.Pointer(cname)) 72 | 73 | return togo(C.PyImport_ExecCodeModule(cname, toc(co))) 74 | } 75 | 76 | //PyImport_ExecCodeModuleEx : https://docs.python.org/3/c-api/import.html#c.PyImport_ExecCodeModuleEx 77 | func PyImport_ExecCodeModuleEx(name string, co *PyObject, pathname string) *PyObject { 78 | cname := C.CString(name) 79 | defer C.free(unsafe.Pointer(cname)) 80 | 81 | cpathname := C.CString(pathname) 82 | defer C.free(unsafe.Pointer(cpathname)) 83 | 84 | return togo(C.PyImport_ExecCodeModuleEx(cname, toc(co), cpathname)) 85 | } 86 | 87 | //PyImport_ExecCodeModuleObject : https://docs.python.org/3/c-api/import.html#c.PyImport_ExecCodeModuleObject 88 | func PyImport_ExecCodeModuleObject(name, co, pathname, cpathname *PyObject) *PyObject { 89 | return togo(C.PyImport_ExecCodeModuleObject(toc(name), toc(co), toc(pathname), toc(cpathname))) 90 | } 91 | 92 | //PyImport_ExecCodeModuleWithPathnames : https://docs.python.org/3/c-api/import.html#c.PyImport_ExecCodeModuleWithPathnames 93 | func PyImport_ExecCodeModuleWithPathnames(name string, co *PyObject, pathname string, cpathname string) *PyObject { 94 | cname := C.CString(name) 95 | defer C.free(unsafe.Pointer(cname)) 96 | 97 | cspathname := C.CString(pathname) 98 | defer C.free(unsafe.Pointer(cspathname)) 99 | 100 | ccpathname := C.CString(cpathname) 101 | defer C.free(unsafe.Pointer(ccpathname)) 102 | 103 | return togo(C.PyImport_ExecCodeModuleWithPathnames(cname, toc(co), cspathname, ccpathname)) 104 | } 105 | 106 | //PyImport_GetMagicNumber : https://docs.python.org/3/c-api/import.html#c.PyImport_GetMagicNumber 107 | func PyImport_GetMagicNumber() int { 108 | return int(C.PyImport_GetMagicNumber()) 109 | } 110 | 111 | //PyImport_GetMagicTag : https://docs.python.org/3/c-api/import.html#c.PyImport_GetMagicTag 112 | func PyImport_GetMagicTag() string { 113 | cmagicTag := C.PyImport_GetMagicTag() 114 | 115 | return C.GoString(cmagicTag) 116 | } 117 | 118 | //PyImport_GetModuleDict : https://docs.python.org/3/c-api/import.html#c.PyImport_GetModuleDict 119 | func PyImport_GetModuleDict() *PyObject { 120 | return togo(C.PyImport_GetModuleDict()) 121 | } 122 | 123 | //PyImport_GetModule : https://docs.python.org/3/c-api/import.html#c.PyImport_GetModule 124 | func PyImport_GetModule(name *PyObject) *PyObject { 125 | return togo(C.PyImport_GetModule(toc(name))) 126 | 127 | } 128 | 129 | //PyImport_GetImporter : https://docs.python.org/3/c-api/import.html#c.PyImport_GetImporter 130 | func PyImport_GetImporter(path *PyObject) *PyObject { 131 | return togo(C.PyImport_GetImporter(toc(path))) 132 | 133 | } 134 | 135 | //PyImport_ImportFrozenModuleObject : https://docs.python.org/3/c-api/import.html#c.PyImport_ImportFrozenModuleObject 136 | func PyImport_ImportFrozenModuleObject(name *PyObject) int { 137 | return int(C.PyImport_ImportFrozenModuleObject(toc(name))) 138 | 139 | } 140 | 141 | //PyImport_ImportFrozenModule : https://docs.python.org/3/c-api/import.html#c.PyImport_ImportFrozenModule 142 | func PyImport_ImportFrozenModule(name string) int { 143 | cname := C.CString(name) 144 | defer C.free(unsafe.Pointer(cname)) 145 | 146 | return int(C.PyImport_ImportFrozenModule(cname)) 147 | 148 | } 149 | -------------------------------------------------------------------------------- /exceptions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | /* 20 | All standard Python exceptions are available as global variables whose names are PyExc_ followed by the Python exception name. 21 | These have the type PyObject*; they are all class objects. 22 | */ 23 | var ( 24 | PyExc_BaseException = togo(C.PyExc_BaseException) 25 | PyExc_Exception = togo(C.PyExc_Exception) 26 | PyExc_ArithmeticError = togo(C.PyExc_ArithmeticError) 27 | PyExc_AssertionError = togo(C.PyExc_AssertionError) 28 | PyExc_AttributeError = togo(C.PyExc_AttributeError) 29 | PyExc_BlockingIOError = togo(C.PyExc_BlockingIOError) 30 | PyExc_BrokenPipeError = togo(C.PyExc_BrokenPipeError) 31 | PyExc_BufferError = togo(C.PyExc_BufferError) 32 | PyExc_ChildProcessError = togo(C.PyExc_ChildProcessError) 33 | PyExc_ConnectionAbortedError = togo(C.PyExc_ConnectionAbortedError) 34 | PyExc_ConnectionError = togo(C.PyExc_ConnectionError) 35 | PyExc_ConnectionRefusedError = togo(C.PyExc_ConnectionRefusedError) 36 | PyExc_ConnectcionResetError = togo(C.PyExc_ConnectionResetError) 37 | PyExc_EOFError = togo(C.PyExc_EOFError) 38 | PyExc_FileExistsError = togo(C.PyExc_FileExistsError) 39 | PyExc_FileNotFoundError = togo(C.PyExc_FileNotFoundError) 40 | PyExc_FloatingPointError = togo(C.PyExc_FloatingPointError) 41 | PyExc_GeneratorExit = togo(C.PyExc_GeneratorExit) 42 | PyExc_ImportError = togo(C.PyExc_ImportError) 43 | PyExc_IndentationError = togo(C.PyExc_IndentationError) 44 | PyExc_IndexError = togo(C.PyExc_IndexError) 45 | PyExc_InterruptedError = togo(C.PyExc_InterruptedError) 46 | PyExc_IsADirectoryError = togo(C.PyExc_IsADirectoryError) 47 | PyExc_KeyError = togo(C.PyExc_KeyError) 48 | PyExc_KeyboardInterrupt = togo(C.PyExc_KeyboardInterrupt) 49 | PyExc_LookupError = togo(C.PyExc_LookupError) 50 | PyExc_MemoryError = togo(C.PyExc_MemoryError) 51 | PyExc_ModuleNotFoundError = togo(C.PyExc_ModuleNotFoundError) 52 | PyExc_NameError = togo(C.PyExc_NameError) 53 | PyExc_NotADirectoryError = togo(C.PyExc_NotADirectoryError) 54 | PyExc_NotImplementedError = togo(C.PyExc_NotImplementedError) 55 | PyExc_OSError = togo(C.PyExc_OSError) 56 | PyExc_OverflowError = togo(C.PyExc_OverflowError) 57 | PyExc_PermissionError = togo(C.PyExc_PermissionError) 58 | PyExc_ProcessLookupError = togo(C.PyExc_ProcessLookupError) 59 | PyExc_RecursionError = togo(C.PyExc_RecursionError) 60 | PyExc_ReferenceError = togo(C.PyExc_ReferenceError) 61 | PyExc_RuntimeError = togo(C.PyExc_RuntimeError) 62 | PyExc_StopAsyncIteration = togo(C.PyExc_StopAsyncIteration) 63 | PyExc_StopIteration = togo(C.PyExc_StopIteration) 64 | PyExc_SyntaxError = togo(C.PyExc_SyntaxError) 65 | PyExc_SystemError = togo(C.PyExc_SystemError) 66 | PyExc_SystemExit = togo(C.PyExc_SystemExit) 67 | PyExc_TabError = togo(C.PyExc_TabError) 68 | PyExc_TimeoutError = togo(C.PyExc_TimeoutError) 69 | PyExc_TypeError = togo(C.PyExc_TypeError) 70 | PyExc_UnboundLocalError = togo(C.PyExc_UnboundLocalError) 71 | PyExc_UnicodeDecodeError = togo(C.PyExc_UnicodeDecodeError) 72 | PyExc_UnicodeEncodeError = togo(C.PyExc_UnicodeEncodeError) 73 | PyExc_UnicodeError = togo(C.PyExc_UnicodeError) 74 | PyExc_UnicodeTranslateError = togo(C.PyExc_UnicodeTranslateError) 75 | PyExc_ValueError = togo(C.PyExc_ValueError) 76 | PyExc_ZeroDivisionError = togo(C.PyExc_ZeroDivisionError) 77 | ) 78 | 79 | //PyErr_NewException : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NewException 80 | func PyErr_NewException(name string, base, dict *PyObject) *PyObject { 81 | cname := C.CString(name) 82 | defer C.free(unsafe.Pointer(cname)) 83 | 84 | return togo(C.PyErr_NewException(cname, toc(base), toc(dict))) 85 | } 86 | 87 | //PyErr_NewExceptionWithDoc : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NewExceptionWithDoc 88 | func PyErr_NewExceptionWithDoc(name, doc string, base, dict *PyObject) *PyObject { 89 | cname := C.CString(name) 90 | defer C.free(unsafe.Pointer(cname)) 91 | 92 | cdoc := C.CString(doc) 93 | defer C.free(unsafe.Pointer(cdoc)) 94 | 95 | return togo(C.PyErr_NewExceptionWithDoc(cname, cdoc, toc(base), toc(dict))) 96 | } 97 | 98 | //PyException_GetTraceback : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetTraceback 99 | func PyException_GetTraceback(ex *PyObject) *PyObject { 100 | return togo(C.PyException_GetTraceback(toc(ex))) 101 | } 102 | 103 | //PyException_SetTraceback : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetTraceback 104 | func PyException_SetTraceback(ex, tb *PyObject) int { 105 | return int(C.PyException_SetTraceback(toc(ex), toc(tb))) 106 | } 107 | 108 | //PyException_GetContext : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetContext 109 | func PyException_GetContext(ex *PyObject) *PyObject { 110 | return togo(C.PyException_GetContext(toc(ex))) 111 | } 112 | 113 | //PyException_SetContext : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetContext 114 | func PyException_SetContext(ex, ctx *PyObject) { 115 | C.PyException_SetContext(toc(ex), toc(ctx)) 116 | } 117 | 118 | //PyException_GetCause : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetCause 119 | func PyException_GetCause(ex *PyObject) *PyObject { 120 | return togo(C.PyException_GetCause(toc(ex))) 121 | } 122 | 123 | //PyException_SetCause : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetCause 124 | func PyException_SetCause(ex, cause *PyObject) { 125 | C.PyException_SetCause(toc(ex), toc(cause)) 126 | } 127 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | 15 | import ( 16 | "unsafe" 17 | ) 18 | 19 | //PyErr_Clear : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear 20 | func PyErr_Clear() { 21 | C.PyErr_Clear() 22 | } 23 | 24 | //PyErr_PrintEx : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_PrintEx 25 | func PyErr_PrintEx(setSysLastVars bool) { 26 | if setSysLastVars { 27 | C.PyErr_PrintEx(1) 28 | } else { 29 | C.PyErr_PrintEx(0) 30 | } 31 | } 32 | 33 | //PyErr_Print : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Print 34 | func PyErr_Print() { 35 | C.PyErr_PrintEx(1) 36 | } 37 | 38 | //PyErr_WriteUnraisable : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable 39 | func PyErr_WriteUnraisable(obj *PyObject) { 40 | C.PyErr_WriteUnraisable(toc(obj)) 41 | } 42 | 43 | //PyErr_SetString : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetString 44 | func PyErr_SetString(pyType *PyObject, message string) { 45 | cmessage := C.CString(message) 46 | defer C.free(unsafe.Pointer(cmessage)) 47 | 48 | C.PyErr_SetString(toc(pyType), cmessage) 49 | 50 | } 51 | 52 | //PyErr_SetObject : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetObject 53 | func PyErr_SetObject(pyType, value *PyObject) { 54 | C.PyErr_SetObject(toc(pyType), toc(value)) 55 | } 56 | 57 | //PyErr_SetNone : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetNone 58 | func PyErr_SetNone(pyType *PyObject) { 59 | C.PyErr_SetNone(toc(pyType)) 60 | } 61 | 62 | //PyErr_BadArgument : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_BadArgument 63 | func PyErr_BadArgument() { 64 | C.PyErr_BadArgument() 65 | } 66 | 67 | //PyErr_NoMemory : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NoMemory 68 | func PyErr_NoMemory() *PyObject { 69 | return togo(C.PyErr_NoMemory()) 70 | } 71 | 72 | //PyErr_SetImportErrorSubclass : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetImportErrorSubclass 73 | func PyErr_SetImportErrorSubclass(msg, name, path, subclass *PyObject) *PyObject { 74 | return togo(C.PyErr_SetImportErrorSubclass(toc(msg), toc(name), toc(path), toc(subclass))) 75 | } 76 | 77 | //PyErr_SetImportError : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetImportError 78 | func PyErr_SetImportError(msg, name, path *PyObject) *PyObject { 79 | return togo(C.PyErr_SetImportError(toc(msg), toc(name), toc(path))) 80 | } 81 | 82 | //PyErr_SyntaxLocationObject : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SyntaxLocationObject 83 | func PyErr_SyntaxLocationObject(filename *PyObject, lineno, col_offset int) { 84 | C.PyErr_SyntaxLocationObject(toc(filename), C.int(lineno), C.int(col_offset)) 85 | } 86 | 87 | //PyErr_SyntaxLocationEx : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SyntaxLocationEx 88 | func PyErr_SyntaxLocationEx(filename string, lineno, col_offset int) { 89 | cfilename := C.CString(filename) 90 | defer C.free(unsafe.Pointer(cfilename)) 91 | 92 | C.PyErr_SyntaxLocationEx(cfilename, C.int(lineno), C.int(col_offset)) 93 | } 94 | 95 | //PyErr_SyntaxLocation : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SyntaxLocation 96 | func PyErr_SyntaxLocation(filename string, lineno int) { 97 | cfilename := C.CString(filename) 98 | defer C.free(unsafe.Pointer(cfilename)) 99 | 100 | C.PyErr_SyntaxLocation(cfilename, C.int(lineno)) 101 | 102 | } 103 | 104 | //PyErr_BadInternalCall : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_BadInternalCall 105 | func PyErr_BadInternalCall() { 106 | C.PyErr_BadInternalCall() 107 | } 108 | 109 | //PyErr_Occurred : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Occurred 110 | func PyErr_Occurred() *PyObject { 111 | return togo(C.PyErr_Occurred()) 112 | } 113 | 114 | //PyErr_GivenExceptionMatches : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_GivenExceptionMatches 115 | func PyErr_GivenExceptionMatches(given, exc *PyObject) bool { 116 | ret := C.PyErr_GivenExceptionMatches(toc(given), toc(exc)) 117 | return ret == 1 118 | } 119 | 120 | //PyErr_ExceptionMatches : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_ExceptionMatches 121 | func PyErr_ExceptionMatches(exc *PyObject) bool { 122 | ret := C.PyErr_ExceptionMatches(toc(exc)) 123 | return ret == 1 124 | } 125 | 126 | //PyErr_Fetch : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Fetch 127 | func PyErr_Fetch() (*PyObject, *PyObject, *PyObject) { 128 | var pyType, value, traceback *C.PyObject 129 | C.PyErr_Fetch(&pyType, &value, &traceback) 130 | return togo(pyType), togo(value), togo(traceback) 131 | } 132 | 133 | //PyErr_Restore : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Restore 134 | func PyErr_Restore(pyType *PyObject, value *PyObject, traceback *PyObject) { 135 | C.PyErr_Restore(toc(pyType), toc(value), toc(traceback)) 136 | } 137 | 138 | //PyErr_NormalizeException : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_NormalizeException 139 | func PyErr_NormalizeException(exc, val, tb *PyObject) (*PyObject, *PyObject, *PyObject) { 140 | cexc := toc(exc) 141 | cval := toc(val) 142 | ctb := toc(tb) 143 | C.PyErr_NormalizeException(&cexc, &cval, &ctb) 144 | return togo(cexc), togo(cval), togo(ctb) 145 | } 146 | 147 | //PyErr_GetExcInfo : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_GetExcInfo 148 | func PyErr_GetExcInfo() (*PyObject, *PyObject, *PyObject) { 149 | var pyType, value, traceback *C.PyObject 150 | C.PyErr_GetExcInfo(&pyType, &value, &traceback) 151 | return togo(pyType), togo(value), togo(traceback) 152 | } 153 | 154 | //PyErr_SetExcInfo : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetExcInfo 155 | func PyErr_SetExcInfo(pyType *PyObject, value *PyObject, traceback *PyObject) { 156 | C.PyErr_SetExcInfo(toc(pyType), toc(value), toc(traceback)) 157 | } 158 | 159 | //PyErr_CheckSignals : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_CheckSignals 160 | func PyErr_CheckSignals() int { 161 | return int(C.PyErr_CheckSignals()) 162 | } 163 | 164 | //PyErr_SetInterrupt : https://docs.python.org/3/c-api/exceptions.html#c.PyErr_SetInterrupt 165 | func PyErr_SetInterrupt() { 166 | C.PyErr_SetInterrupt() 167 | } 168 | -------------------------------------------------------------------------------- /errors_test.go: -------------------------------------------------------------------------------- 1 | package python3 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestErrorSetString(t *testing.T) { 10 | Py_Initialize() 11 | 12 | PyErr_SetString(PyExc_BaseException, "test message") 13 | 14 | assert.NotNil(t, PyErr_Occurred()) 15 | PyErr_Clear() 16 | assert.Nil(t, PyErr_Occurred()) 17 | } 18 | 19 | func TestErrorSetObject(t *testing.T) { 20 | Py_Initialize() 21 | 22 | message := PyUnicode_FromString("test message") 23 | defer message.DecRef() 24 | 25 | PyErr_SetObject(PyExc_BaseException, message) 26 | 27 | assert.NotNil(t, PyErr_Occurred()) 28 | PyErr_Print() 29 | assert.Nil(t, PyErr_Occurred()) 30 | } 31 | 32 | func TestErrorSetNone(t *testing.T) { 33 | Py_Initialize() 34 | 35 | message := PyUnicode_FromString("test message") 36 | defer message.DecRef() 37 | 38 | PyErr_SetNone(PyExc_BaseException) 39 | 40 | assert.NotNil(t, PyErr_Occurred()) 41 | PyErr_Print() 42 | assert.Nil(t, PyErr_Occurred()) 43 | } 44 | 45 | func TestErrorSetObjectEx(t *testing.T) { 46 | Py_Initialize() 47 | 48 | message := PyUnicode_FromString("test message") 49 | defer message.DecRef() 50 | 51 | PyErr_SetObject(PyExc_BaseException, message) 52 | 53 | assert.NotNil(t, PyErr_Occurred()) 54 | PyErr_PrintEx(false) 55 | assert.Nil(t, PyErr_Occurred()) 56 | } 57 | 58 | func TestErrorWriteUnraisable(t *testing.T) { 59 | Py_Initialize() 60 | 61 | message := PyUnicode_FromString("unraisable exception") 62 | defer message.DecRef() 63 | 64 | PyErr_WriteUnraisable(message) 65 | 66 | assert.Nil(t, PyErr_Occurred()) 67 | } 68 | 69 | func TestErrorBadArgument(t *testing.T) { 70 | Py_Initialize() 71 | 72 | PyErr_BadArgument() 73 | 74 | assert.NotNil(t, PyErr_Occurred()) 75 | 76 | PyErr_Clear() 77 | 78 | assert.Nil(t, PyErr_Occurred()) 79 | } 80 | 81 | func TestErrorNoMemory(t *testing.T) { 82 | Py_Initialize() 83 | 84 | PyErr_NoMemory() 85 | 86 | assert.NotNil(t, PyErr_Occurred()) 87 | PyErr_Clear() 88 | assert.Nil(t, PyErr_Occurred()) 89 | } 90 | 91 | func TestErrorBadInternalCall(t *testing.T) { 92 | Py_Initialize() 93 | 94 | PyErr_BadInternalCall() 95 | 96 | assert.NotNil(t, PyErr_Occurred()) 97 | PyErr_Clear() 98 | assert.Nil(t, PyErr_Occurred()) 99 | } 100 | 101 | func TestErrorImportError(t *testing.T) { 102 | Py_Initialize() 103 | 104 | message := PyUnicode_FromString("test message") 105 | defer message.DecRef() 106 | 107 | PyErr_SetImportError(message, nil, nil) 108 | 109 | assert.NotNil(t, PyErr_Occurred()) 110 | PyErr_Clear() 111 | assert.Nil(t, PyErr_Occurred()) 112 | } 113 | 114 | func TestErrorImportErrorSubclass(t *testing.T) { 115 | Py_Initialize() 116 | 117 | message := PyUnicode_FromString("test message") 118 | defer message.DecRef() 119 | 120 | PyErr_SetImportErrorSubclass(message, nil, nil, Dict) 121 | 122 | assert.NotNil(t, PyErr_Occurred()) 123 | PyErr_Clear() 124 | assert.Nil(t, PyErr_Occurred()) 125 | } 126 | 127 | func TestErrorSyntax(t *testing.T) { 128 | Py_Initialize() 129 | 130 | PyErr_SetNone(PyExc_SyntaxError) 131 | 132 | filename := "test.py" 133 | PyErr_SyntaxLocation(filename, 0) 134 | 135 | assert.NotNil(t, PyErr_Occurred()) 136 | PyErr_Clear() 137 | assert.Nil(t, PyErr_Occurred()) 138 | } 139 | 140 | func TestErrorSyntaxEx(t *testing.T) { 141 | Py_Initialize() 142 | 143 | PyErr_SetNone(PyExc_SyntaxError) 144 | 145 | filename := "test.py" 146 | PyErr_SyntaxLocationEx(filename, 0, 0) 147 | 148 | assert.NotNil(t, PyErr_Occurred()) 149 | PyErr_Clear() 150 | assert.Nil(t, PyErr_Occurred()) 151 | } 152 | 153 | func TestErrorSyntaxLocation(t *testing.T) { 154 | Py_Initialize() 155 | 156 | PyErr_SetNone(PyExc_SyntaxError) 157 | 158 | filename := PyUnicode_FromString("test.py") 159 | defer filename.DecRef() 160 | 161 | PyErr_SyntaxLocationObject(filename, 0, 0) 162 | 163 | assert.NotNil(t, PyErr_Occurred()) 164 | PyErr_Clear() 165 | assert.Nil(t, PyErr_Occurred()) 166 | } 167 | 168 | func TestErrorExceptionMatches(t *testing.T) { 169 | Py_Initialize() 170 | 171 | PyErr_SetNone(PyExc_BufferError) 172 | 173 | assert.True(t, PyErr_ExceptionMatches(PyExc_BufferError)) 174 | 175 | assert.NotNil(t, PyErr_Occurred()) 176 | PyErr_Clear() 177 | assert.Nil(t, PyErr_Occurred()) 178 | } 179 | 180 | func TestErrorGivenExceptionMatches(t *testing.T) { 181 | Py_Initialize() 182 | 183 | assert.True(t, PyErr_GivenExceptionMatches(PyExc_BufferError, PyExc_BufferError)) 184 | } 185 | 186 | func TestErrorFetchRestore(t *testing.T) { 187 | Py_Initialize() 188 | 189 | PyErr_SetNone(PyExc_BufferError) 190 | 191 | exc, value, traceback := PyErr_Fetch() 192 | assert.Nil(t, PyErr_Occurred()) 193 | 194 | assert.True(t, PyErr_GivenExceptionMatches(exc, PyExc_BufferError)) 195 | assert.Nil(t, value) 196 | assert.Nil(t, traceback) 197 | 198 | PyErr_Restore(exc, value, traceback) 199 | 200 | assert.NotNil(t, PyErr_Occurred()) 201 | PyErr_Clear() 202 | assert.Nil(t, PyErr_Occurred()) 203 | } 204 | 205 | func TestErrorNormalizeExceptionRestore(t *testing.T) { 206 | Py_Initialize() 207 | 208 | PyErr_SetNone(PyExc_BufferError) 209 | 210 | exc, value, traceback := PyErr_Fetch() 211 | exc, value, traceback = PyErr_NormalizeException(exc, value, traceback) 212 | assert.Nil(t, PyErr_Occurred()) 213 | 214 | assert.True(t, PyErr_GivenExceptionMatches(exc, PyExc_BufferError)) 215 | assert.Equal(t, 1, value.IsInstance(exc)) 216 | assert.Nil(t, traceback) 217 | 218 | PyErr_Restore(exc, value, traceback) 219 | 220 | assert.NotNil(t, PyErr_Occurred()) 221 | PyErr_Clear() 222 | assert.Nil(t, PyErr_Occurred()) 223 | } 224 | 225 | func TestErrorGetSetExcInfo(t *testing.T) { 226 | Py_Initialize() 227 | 228 | PyErr_SetNone(PyExc_BufferError) 229 | 230 | exc, value, traceback := PyErr_GetExcInfo() 231 | 232 | assert.True(t, PyErr_GivenExceptionMatches(exc, Py_None), PyUnicode_AsUTF8(exc.Repr())) 233 | assert.Nil(t, value) 234 | assert.Nil(t, traceback) 235 | 236 | PyErr_SetExcInfo(exc, value, traceback) 237 | 238 | PyErr_Clear() 239 | assert.Nil(t, PyErr_Occurred()) 240 | } 241 | 242 | func TestErrorInterrupt(t *testing.T) { 243 | Py_Initialize() 244 | 245 | PyErr_SetInterrupt() 246 | 247 | assert.Equal(t, -1, PyErr_CheckSignals()) 248 | 249 | exc := PyErr_Occurred() 250 | assert.True(t, PyErr_GivenExceptionMatches(exc, PyExc_TypeError)) 251 | 252 | assert.NotNil(t, PyErr_Occurred()) 253 | PyErr_Clear() 254 | assert.Nil(t, PyErr_Occurred()) 255 | } 256 | -------------------------------------------------------------------------------- /import_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestImportModule(t *testing.T) { 17 | Py_Initialize() 18 | 19 | os := PyImport_ImportModule("os") 20 | assert.NotNil(t, os) 21 | os.DecRef() 22 | } 23 | 24 | func TestImportModuleEx(t *testing.T) { 25 | Py_Initialize() 26 | 27 | test := PyImport_ImportModuleEx("test", nil, nil, nil) 28 | assert.NotNil(t, test) 29 | test.DecRef() 30 | } 31 | 32 | func TestImportModuleLevelObject(t *testing.T) { 33 | Py_Initialize() 34 | 35 | mathName := PyUnicode_FromString("math") 36 | defer mathName.DecRef() 37 | 38 | math := PyImport_ImportModuleLevelObject(mathName, nil, nil, nil, 0) 39 | assert.NotNil(t, math) 40 | math.DecRef() 41 | } 42 | 43 | func TestImportModuleLevel(t *testing.T) { 44 | Py_Initialize() 45 | 46 | sys := PyImport_ImportModuleLevel("sys", nil, nil, nil, 0) 47 | assert.NotNil(t, sys) 48 | sys.DecRef() 49 | } 50 | 51 | func TestImportImport(t *testing.T) { 52 | Py_Initialize() 53 | 54 | platformName := PyUnicode_FromString("platform") 55 | defer platformName.DecRef() 56 | 57 | platform := PyImport_Import(platformName) 58 | assert.NotNil(t, platform) 59 | platform.DecRef() 60 | } 61 | 62 | func TestReloadModule(t *testing.T) { 63 | Py_Initialize() 64 | 65 | os := PyImport_ImportModule("os") 66 | assert.NotNil(t, os) 67 | defer os.DecRef() 68 | 69 | newOs := PyImport_ReloadModule(os) 70 | assert.NotNil(t, newOs) 71 | defer newOs.DecRef() 72 | 73 | // PyImport_ReloadModule return a new reference, pointer should be the same 74 | assert.Equal(t, os, newOs) 75 | } 76 | 77 | func TestAddModuleObject(t *testing.T) { 78 | Py_Initialize() 79 | 80 | os := PyImport_ImportModule("os") 81 | assert.NotNil(t, os) 82 | defer os.DecRef() 83 | 84 | pyName := PyUnicode_FromString("os.new") 85 | defer pyName.DecRef() 86 | 87 | new := PyImport_AddModuleObject(pyName) 88 | assert.NotNil(t, new) 89 | } 90 | 91 | func TestAddModule(t *testing.T) { 92 | Py_Initialize() 93 | 94 | os := PyImport_ImportModule("os") 95 | assert.NotNil(t, os) 96 | defer os.DecRef() 97 | 98 | new := PyImport_AddModule("os.new") 99 | assert.NotNil(t, new) 100 | } 101 | 102 | func TestExecCodeModule(t *testing.T) { 103 | Py_Initialize() 104 | 105 | // fake module 106 | source := PyUnicode_FromString("__version__ = '2.0'") 107 | defer source.DecRef() 108 | filename := PyUnicode_FromString("test_module.py") 109 | defer filename.DecRef() 110 | mode := PyUnicode_FromString("exec") 111 | defer mode.DecRef() 112 | 113 | // perform module load 114 | builtins := PyEval_GetBuiltins() 115 | assert.True(t, PyDict_Check(builtins)) 116 | 117 | compile := PyDict_GetItemString(builtins, "compile") 118 | assert.True(t, PyCallable_Check(compile)) 119 | 120 | code := compile.CallFunctionObjArgs(source, filename, mode) 121 | assert.NotNil(t, code) 122 | defer code.DecRef() 123 | 124 | module := PyImport_ExecCodeModule("test_module", code) 125 | assert.NotNil(t, module) 126 | 127 | } 128 | 129 | func TestExecCodeModuleEx(t *testing.T) { 130 | Py_Initialize() 131 | 132 | // fake module 133 | source := PyUnicode_FromString("__version__ = '2.0'") 134 | defer source.DecRef() 135 | filename := PyUnicode_FromString("test_module.py") 136 | defer filename.DecRef() 137 | mode := PyUnicode_FromString("exec") 138 | defer mode.DecRef() 139 | 140 | // perform module load 141 | builtins := PyEval_GetBuiltins() 142 | assert.True(t, PyDict_Check(builtins)) 143 | 144 | compile := PyDict_GetItemString(builtins, "compile") 145 | assert.True(t, PyCallable_Check(compile)) 146 | 147 | code := compile.CallFunctionObjArgs(source, filename, mode) 148 | assert.NotNil(t, code) 149 | defer code.DecRef() 150 | 151 | module := PyImport_ExecCodeModuleEx("test_module", code, "test_module.py") 152 | assert.NotNil(t, module) 153 | 154 | } 155 | 156 | func TestExecCodeModuleWithPathnames(t *testing.T) { 157 | Py_Initialize() 158 | 159 | // fake module 160 | source := PyUnicode_FromString("__version__ = '2.0'") 161 | defer source.DecRef() 162 | filename := PyUnicode_FromString("test_module.py") 163 | defer filename.DecRef() 164 | mode := PyUnicode_FromString("exec") 165 | defer mode.DecRef() 166 | 167 | // perform module load 168 | builtins := PyEval_GetBuiltins() 169 | assert.True(t, PyDict_Check(builtins)) 170 | 171 | compile := PyDict_GetItemString(builtins, "compile") 172 | assert.True(t, PyCallable_Check(compile)) 173 | 174 | code := compile.CallFunctionObjArgs(source, filename, mode) 175 | assert.NotNil(t, code) 176 | defer code.DecRef() 177 | 178 | module := PyImport_ExecCodeModuleWithPathnames("test_module", code, "test_module.py", "test_module.py") 179 | assert.NotNil(t, module) 180 | 181 | } 182 | 183 | func TestExecCodeModuleObject(t *testing.T) { 184 | Py_Initialize() 185 | 186 | // fake module 187 | source := PyUnicode_FromString("__version__ = '2.0'") 188 | defer source.DecRef() 189 | filename := PyUnicode_FromString("test_module.py") 190 | defer filename.DecRef() 191 | mode := PyUnicode_FromString("exec") 192 | defer mode.DecRef() 193 | 194 | // perform module load 195 | builtins := PyEval_GetBuiltins() 196 | assert.True(t, PyDict_Check(builtins)) 197 | 198 | compile := PyDict_GetItemString(builtins, "compile") 199 | assert.True(t, PyCallable_Check(compile)) 200 | 201 | code := compile.CallFunctionObjArgs(source, filename, mode) 202 | assert.NotNil(t, code) 203 | defer code.DecRef() 204 | 205 | moduleName := PyUnicode_FromString("test_module") 206 | defer moduleName.DecRef() 207 | 208 | module := PyImport_ExecCodeModuleObject(moduleName, code, filename, filename) 209 | assert.NotNil(t, module) 210 | 211 | } 212 | 213 | func TestGetMagicNumber(t *testing.T) { 214 | Py_Initialize() 215 | 216 | magicNumber := PyImport_GetMagicNumber() 217 | assert.NotNil(t, magicNumber) 218 | } 219 | 220 | func TestGetMagicTag(t *testing.T) { 221 | Py_Initialize() 222 | 223 | magicTag := PyImport_GetMagicTag() 224 | assert.NotNil(t, magicTag) 225 | } 226 | 227 | func TestGetModuleDict(t *testing.T) { 228 | Py_Initialize() 229 | 230 | moduleDict := PyImport_GetModuleDict() 231 | defer moduleDict.DecRef() 232 | 233 | assert.True(t, PyDict_Check(moduleDict)) 234 | 235 | } 236 | 237 | func TestGetModule(t *testing.T) { 238 | Py_Initialize() 239 | 240 | os := PyImport_ImportModule("os") 241 | assert.NotNil(t, os) 242 | defer os.DecRef() 243 | 244 | name := PyUnicode_FromString("os") 245 | defer name.DecRef() 246 | 247 | new := PyImport_GetModule(name) 248 | assert.Equal(t, new, os) 249 | } 250 | 251 | func TestGetImporter(t *testing.T) { 252 | Py_Initialize() 253 | 254 | paths := PySys_GetObject("path") 255 | path := PyList_GetItem(paths, 0) 256 | 257 | assert.NotNil(t, path) 258 | importer := PyImport_GetImporter(path) 259 | defer importer.DecRef() 260 | 261 | assert.NotNil(t, importer) 262 | 263 | } 264 | -------------------------------------------------------------------------------- /variadic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | #include "Python.h" 9 | 10 | PyObject* _go_PyObject_CallFunctionObjArgs(PyObject *callable, int argc, PyObject **argv) { 11 | 12 | PyObject *result = NULL; 13 | switch (argc) { 14 | case 0: 15 | return PyObject_CallFunctionObjArgs(callable, NULL); 16 | case 1: 17 | return PyObject_CallFunctionObjArgs(callable, argv[0], NULL); 18 | case 2: 19 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], NULL); 20 | case 3: 21 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], NULL); 22 | case 4: 23 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], NULL); 24 | case 5: 25 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], NULL); 26 | case 6: 27 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); 28 | case 7: 29 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], NULL); 30 | case 8: 31 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], NULL); 32 | case 9: 33 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], NULL); 34 | case 10: 35 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], NULL); 36 | case 11: 37 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], NULL); 38 | case 12: 39 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], NULL); 40 | case 13: 41 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], NULL); 42 | case 14: 43 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], NULL); 44 | case 15: 45 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], NULL); 46 | case 16: 47 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], NULL); 48 | case 17: 49 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], NULL); 50 | case 18: 51 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], NULL); 52 | case 19: 53 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], NULL); 54 | case 20: 55 | return PyObject_CallFunctionObjArgs(callable, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], NULL); 56 | } 57 | return result; 58 | } 59 | PyObject* _go_PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, int argc, PyObject **argv) { 60 | 61 | PyObject *result = NULL; 62 | switch (argc) { 63 | case 0: 64 | return PyObject_CallMethodObjArgs(obj, name, NULL); 65 | case 1: 66 | return PyObject_CallMethodObjArgs(obj, name, argv[0], NULL); 67 | case 2: 68 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], NULL); 69 | case 3: 70 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], NULL); 71 | case 4: 72 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], NULL); 73 | case 5: 74 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], NULL); 75 | case 6: 76 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], NULL); 77 | case 7: 78 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], NULL); 79 | case 8: 80 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], NULL); 81 | case 9: 82 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], NULL); 83 | case 10: 84 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], NULL); 85 | case 11: 86 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], NULL); 87 | case 12: 88 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], NULL); 89 | case 13: 90 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], NULL); 91 | case 14: 92 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], NULL); 93 | case 15: 94 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], NULL); 95 | case 16: 96 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], NULL); 97 | case 17: 98 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], NULL); 99 | case 18: 100 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], NULL); 101 | case 19: 102 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], NULL); 103 | case 20: 104 | return PyObject_CallMethodObjArgs(obj, name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18], argv[19], NULL); 105 | } 106 | return result; 107 | } 108 | -------------------------------------------------------------------------------- /object_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | import ( 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestAttrString(t *testing.T) { 17 | Py_Initialize() 18 | 19 | sys := PyImport_ImportModule("sys") 20 | defer sys.DecRef() 21 | 22 | assert.True(t, sys.HasAttrString("stdout")) 23 | stdout := sys.GetAttrString("stdout") 24 | assert.NotNil(t, stdout) 25 | 26 | assert.Zero(t, sys.DelAttrString("stdout")) 27 | 28 | assert.Nil(t, sys.GetAttrString("stdout")) 29 | PyErr_Clear() 30 | 31 | assert.Zero(t, sys.SetAttrString("stdout", stdout)) 32 | 33 | } 34 | 35 | func TestAttr(t *testing.T) { 36 | Py_Initialize() 37 | 38 | name := PyUnicode_FromString("stdout") 39 | defer name.DecRef() 40 | 41 | sys := PyImport_ImportModule("sys") 42 | defer sys.DecRef() 43 | 44 | assert.True(t, sys.HasAttr(name)) 45 | stdout := sys.GetAttr(name) 46 | assert.NotNil(t, stdout) 47 | 48 | assert.Zero(t, sys.DelAttr(name)) 49 | 50 | assert.Nil(t, sys.GetAttr(name)) 51 | PyErr_Clear() 52 | 53 | assert.Zero(t, sys.SetAttr(name, stdout)) 54 | } 55 | 56 | func TestRichCompareBool(t *testing.T) { 57 | Py_Initialize() 58 | 59 | s1 := PyUnicode_FromString("test1") 60 | s2 := PyUnicode_FromString("test2") 61 | 62 | assert.Zero(t, s1.RichCompareBool(s2, Py_EQ)) 63 | 64 | assert.NotZero(t, s1.RichCompareBool(s1, Py_EQ)) 65 | 66 | } 67 | 68 | func TestRichCompare(t *testing.T) { 69 | Py_Initialize() 70 | 71 | s1 := PyUnicode_FromString("test1") 72 | s2 := PyUnicode_FromString("test2") 73 | 74 | b1 := s1.RichCompare(s2, Py_EQ) 75 | defer b1.DecRef() 76 | assert.Equal(t, Py_False, b1) 77 | 78 | b2 := s1.RichCompare(s1, Py_EQ) 79 | assert.Equal(t, Py_True, b2) 80 | defer b2.DecRef() 81 | 82 | } 83 | 84 | func TestRepr(t *testing.T) { 85 | Py_Initialize() 86 | 87 | list := PyList_New(0) 88 | defer list.DecRef() 89 | 90 | repr := list.Repr() 91 | 92 | assert.Equal(t, "[]", PyUnicode_AsUTF8(repr)) 93 | } 94 | 95 | func TestStr(t *testing.T) { 96 | Py_Initialize() 97 | 98 | list := PyList_New(0) 99 | defer list.DecRef() 100 | 101 | str := list.Str() 102 | 103 | assert.Equal(t, "[]", PyUnicode_AsUTF8(str)) 104 | } 105 | 106 | func TestASCII(t *testing.T) { 107 | Py_Initialize() 108 | 109 | list := PyList_New(0) 110 | defer list.DecRef() 111 | 112 | ascii := list.ASCII() 113 | 114 | assert.Equal(t, "[]", PyUnicode_AsUTF8(ascii)) 115 | } 116 | 117 | func TestCallable(t *testing.T) { 118 | Py_Initialize() 119 | 120 | builtins := PyEval_GetBuiltins() 121 | assert.True(t, PyDict_Check(builtins)) 122 | 123 | len := PyDict_GetItemString(builtins, "len") 124 | assert.True(t, PyCallable_Check(len)) 125 | 126 | emptyList := PyList_New(0) 127 | assert.True(t, PyList_Check(emptyList)) 128 | 129 | args := PyTuple_New(1) 130 | defer args.DecRef() 131 | assert.True(t, PyTuple_Check(args)) 132 | 133 | PyTuple_SetItem(args, 0, emptyList) 134 | 135 | length := len.Call(args, nil) 136 | assert.True(t, PyLong_Check(length)) 137 | assert.Equal(t, 0, PyLong_AsLong(length)) 138 | length.DecRef() 139 | 140 | length = len.CallObject(args) 141 | assert.True(t, PyLong_Check(length)) 142 | assert.Equal(t, 0, PyLong_AsLong(length)) 143 | length.DecRef() 144 | 145 | length = len.CallFunctionObjArgs(emptyList) 146 | assert.True(t, PyLong_Check(length)) 147 | assert.Equal(t, 0, PyLong_AsLong(length)) 148 | length.DecRef() 149 | 150 | } 151 | 152 | func TestCallMethod(t *testing.T) { 153 | Py_Initialize() 154 | 155 | s := PyUnicode_FromString("hello world") 156 | assert.True(t, PyUnicode_Check(s)) 157 | defer s.DecRef() 158 | 159 | sep := PyUnicode_FromString(" ") 160 | assert.True(t, PyUnicode_Check(sep)) 161 | defer sep.DecRef() 162 | 163 | split := PyUnicode_FromString("split") 164 | assert.True(t, PyUnicode_Check(split)) 165 | defer split.DecRef() 166 | 167 | words := s.CallMethodObjArgs(split, sep) 168 | assert.True(t, PyList_Check(words)) 169 | defer words.DecRef() 170 | assert.Equal(t, 2, PyList_Size(words)) 171 | 172 | hello := PyList_GetItem(words, 0) 173 | assert.True(t, PyUnicode_Check(hello)) 174 | world := PyList_GetItem(words, 1) 175 | assert.True(t, PyUnicode_Check(world)) 176 | 177 | assert.Equal(t, "hello", PyUnicode_AsUTF8(hello)) 178 | assert.Equal(t, "world", PyUnicode_AsUTF8(world)) 179 | 180 | words.DecRef() 181 | 182 | words = s.CallMethodArgs("split", sep) 183 | assert.True(t, PyList_Check(words)) 184 | defer words.DecRef() 185 | assert.Equal(t, 2, PyList_Size(words)) 186 | 187 | hello = PyList_GetItem(words, 0) 188 | assert.True(t, PyUnicode_Check(hello)) 189 | world = PyList_GetItem(words, 1) 190 | assert.True(t, PyUnicode_Check(world)) 191 | 192 | assert.Equal(t, "hello", PyUnicode_AsUTF8(hello)) 193 | assert.Equal(t, "world", PyUnicode_AsUTF8(world)) 194 | 195 | words.DecRef() 196 | 197 | } 198 | 199 | func TestIsTrue(t *testing.T) { 200 | Py_Initialize() 201 | 202 | b := Py_True.IsTrue() != 0 203 | assert.True(t, b) 204 | 205 | b = Py_False.IsTrue() != 0 206 | assert.False(t, b) 207 | } 208 | 209 | func TestNot(t *testing.T) { 210 | Py_Initialize() 211 | 212 | b := Py_True.Not() != 0 213 | assert.False(t, b) 214 | 215 | b = Py_False.Not() != 0 216 | assert.True(t, b) 217 | } 218 | 219 | func TestLength(t *testing.T) { 220 | Py_Initialize() 221 | length := 6 222 | 223 | list := PyList_New(length) 224 | defer list.DecRef() 225 | listLength := list.Length() 226 | 227 | assert.Equal(t, length, listLength) 228 | 229 | } 230 | 231 | func TestLengthHint(t *testing.T) { 232 | Py_Initialize() 233 | length := 6 234 | 235 | list := PyList_New(length) 236 | defer list.DecRef() 237 | listLength := list.LengthHint(0) 238 | 239 | assert.Equal(t, length, listLength) 240 | 241 | } 242 | 243 | func TestObjectItem(t *testing.T) { 244 | Py_Initialize() 245 | 246 | key := PyUnicode_FromString("key") 247 | defer key.DecRef() 248 | value := PyUnicode_FromString("value") 249 | defer value.DecRef() 250 | 251 | dict := PyDict_New() 252 | err := dict.SetItem(key, value) 253 | assert.Zero(t, err) 254 | 255 | dictValue := dict.GetItem(key) 256 | assert.Equal(t, value, dictValue) 257 | 258 | err = dict.DelItem(key) 259 | assert.Zero(t, err) 260 | 261 | } 262 | 263 | func TestDir(t *testing.T) { 264 | Py_Initialize() 265 | 266 | list := PyList_New(0) 267 | defer list.DecRef() 268 | 269 | dir := list.Dir() 270 | defer dir.DecRef() 271 | 272 | repr := dir.Repr() 273 | defer repr.DecRef() 274 | 275 | 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)) 276 | 277 | } 278 | 279 | func TestReprEnterLeave(t *testing.T) { 280 | Py_Initialize() 281 | 282 | s := PyUnicode_FromString("hello world") 283 | defer s.DecRef() 284 | 285 | assert.Zero(t, s.ReprEnter()) 286 | 287 | assert.True(t, s.ReprEnter() > 0) 288 | 289 | s.ReprLeave() 290 | s.ReprLeave() 291 | } 292 | 293 | func TestIsSubclass(t *testing.T) { 294 | Py_Initialize() 295 | 296 | assert.Equal(t, 1, PyExc_Warning.IsSubclass(PyExc_Exception)) 297 | assert.Equal(t, 0, Bool.IsSubclass(Float)) 298 | } 299 | 300 | func TestHash(t *testing.T) { 301 | Py_Initialize() 302 | 303 | s := PyUnicode_FromString("test string") 304 | defer s.DecRef() 305 | 306 | assert.NotEqual(t, -1, s.Hash()) 307 | } 308 | 309 | func TestObjectType(t *testing.T) { 310 | Py_Initialize() 311 | 312 | i := PyLong_FromGoInt(23543) 313 | defer i.DecRef() 314 | 315 | assert.Equal(t, Long, i.Type()) 316 | } 317 | 318 | func TestHashNotImplemented(t *testing.T) { 319 | Py_Initialize() 320 | 321 | s := PyUnicode_FromString("test string") 322 | defer s.DecRef() 323 | 324 | assert.Equal(t, -1, s.HashNotImplemented()) 325 | 326 | assert.True(t, PyErr_ExceptionMatches(PyExc_TypeError)) 327 | 328 | PyErr_Clear() 329 | } 330 | 331 | func TestObjectIter(t *testing.T) { 332 | Py_Initialize() 333 | 334 | i := PyLong_FromGoInt(23) 335 | defer i.DecRef() 336 | 337 | assert.Nil(t, i.GetIter()) 338 | 339 | assert.True(t, PyErr_ExceptionMatches(PyExc_TypeError)) 340 | PyErr_Clear() 341 | 342 | list := PyList_New(23) 343 | defer list.DecRef() 344 | 345 | iter := list.GetIter() 346 | assert.NotNil(t, iter) 347 | defer iter.DecRef() 348 | } 349 | -------------------------------------------------------------------------------- /lifecycle.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | /* 11 | #include "Python.h" 12 | */ 13 | import "C" 14 | import ( 15 | "fmt" 16 | "unsafe" 17 | ) 18 | 19 | // The argument for Py_SetProgramName, Py_SetPath and Py_SetPythonHome should point to a zero-terminated wide character string in static storage 20 | // whose contents will not change for the duration of the program’s execution 21 | var ( 22 | programName *C.wchar_t 23 | pythonPath *C.wchar_t 24 | pythonHome *C.wchar_t 25 | ) 26 | 27 | //Py_Initialize : https://docs.python.org/3/c-api/init.html#c.Py_Initialize 28 | func Py_Initialize() { 29 | C.Py_Initialize() 30 | } 31 | 32 | //Py_InitializeEx : https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx 33 | func Py_InitializeEx(initsigs bool) { 34 | if initsigs { 35 | C.Py_InitializeEx(1) 36 | } else { 37 | C.Py_InitializeEx(0) 38 | } 39 | } 40 | 41 | //Py_IsInitialized : https://docs.python.org/3/c-api/init.html#c.Py_IsInitialized 42 | func Py_IsInitialized() bool { 43 | return C.Py_IsInitialized() != 0 44 | } 45 | 46 | //Py_FinalizeEx : https://docs.python.org/3/c-api/init.html#c.Py_FinalizeEx 47 | func Py_FinalizeEx() int { 48 | return int(C.Py_FinalizeEx()) 49 | } 50 | 51 | //Py_Finalize : https://docs.python.org/3/c-api/init.html#c.Py_Finalize 52 | func Py_Finalize() { 53 | C.Py_Finalize() 54 | } 55 | 56 | //Py_SetStandardStreamEncoding : https://docs.python.org/3/c-api/init.html#c.Py_SetStandardStreamEncoding 57 | func Py_SetStandardStreamEncoding(encoding, errors string) int { 58 | cencoding := C.CString(encoding) 59 | defer C.free(unsafe.Pointer(cencoding)) 60 | 61 | cerrors := C.CString(errors) 62 | defer C.free(unsafe.Pointer(cerrors)) 63 | 64 | return int(C.Py_SetStandardStreamEncoding(cencoding, cerrors)) 65 | 66 | } 67 | 68 | //Py_SetProgramName : https://docs.python.org/3/c-api/init.html#c.Py_SetProgramName 69 | func Py_SetProgramName(name string) error { 70 | cname := C.CString(name) 71 | defer C.free(unsafe.Pointer(cname)) 72 | 73 | newProgramName := C.Py_DecodeLocale(cname, nil) 74 | if newProgramName == nil { 75 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", name) 76 | } 77 | C.Py_SetProgramName(newProgramName) 78 | 79 | //no operation is performed if nil 80 | C.PyMem_RawFree(unsafe.Pointer(programName)) 81 | programName = newProgramName 82 | 83 | return nil 84 | } 85 | 86 | //Py_GetProgramName : https://docs.python.org/3/c-api/init.html#c.Py_GetProgramName 87 | func Py_GetProgramName() (string, error) { 88 | wcname := C.Py_GetProgramName() 89 | if wcname == nil { 90 | return "", nil 91 | } 92 | cname := C.Py_EncodeLocale(wcname, nil) 93 | if cname == nil { 94 | return "", fmt.Errorf("fail to call Py_EncodeLocale") 95 | } 96 | defer C.PyMem_Free(unsafe.Pointer(cname)) 97 | 98 | return C.GoString(cname), nil 99 | } 100 | 101 | //Py_GetPrefix : https://docs.python.org/3/c-api/init.html#c.Py_GetPrefix 102 | func Py_GetPrefix() (string, error) { 103 | wcname := C.Py_GetPrefix() 104 | if wcname == nil { 105 | return "", nil 106 | } 107 | cname := C.Py_EncodeLocale(wcname, nil) 108 | if cname == nil { 109 | return "", fmt.Errorf("fail to call Py_EncodeLocale") 110 | } 111 | defer C.PyMem_Free(unsafe.Pointer(cname)) 112 | 113 | return C.GoString(cname), nil 114 | } 115 | 116 | //Py_GetExecPrefix : https://docs.python.org/3/c-api/init.html#c.Py_GetExecPrefix 117 | func Py_GetExecPrefix() (string, error) { 118 | wcname := C.Py_GetExecPrefix() 119 | if wcname == nil { 120 | return "", nil 121 | } 122 | cname := C.Py_EncodeLocale(wcname, nil) 123 | if cname == nil { 124 | return "", fmt.Errorf("fail to call Py_EncodeLocale") 125 | } 126 | defer C.PyMem_Free(unsafe.Pointer(cname)) 127 | 128 | return C.GoString(cname), nil 129 | } 130 | 131 | //Py_GetProgramFullPath : https://docs.python.org/3/c-api/init.html#c.Py_GetProgramFullPath 132 | func Py_GetProgramFullPath() (string, error) { 133 | wcname := C.Py_GetProgramFullPath() 134 | if wcname == nil { 135 | return "", nil 136 | } 137 | cname := C.Py_EncodeLocale(wcname, nil) 138 | if cname == nil { 139 | return "", fmt.Errorf("fail to call Py_EncodeLocale") 140 | } 141 | defer C.PyMem_Free(unsafe.Pointer(cname)) 142 | 143 | return C.GoString(cname), nil 144 | } 145 | 146 | //Py_GetPath : https://docs.python.org/3/c-api/init.html#c.Py_GetPath 147 | func Py_GetPath() (string, error) { 148 | wcname := C.Py_GetPath() 149 | if wcname == nil { 150 | return "", nil 151 | } 152 | cname := C.Py_EncodeLocale(wcname, nil) 153 | if cname == nil { 154 | return "", fmt.Errorf("fail to call Py_EncodeLocale") 155 | } 156 | defer C.PyMem_Free(unsafe.Pointer(cname)) 157 | 158 | return C.GoString(cname), nil 159 | } 160 | 161 | //Py_SetPath : https://docs.python.org/3/c-api/init.html#c.Py_SetPath 162 | func Py_SetPath(path string) error { 163 | cpath := C.CString(path) 164 | defer C.free(unsafe.Pointer(cpath)) 165 | 166 | newPath := C.Py_DecodeLocale(cpath, nil) 167 | if newPath == nil { 168 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", path) 169 | } 170 | C.Py_SetPath(newPath) 171 | 172 | C.PyMem_RawFree(unsafe.Pointer(pythonPath)) 173 | pythonHome = newPath 174 | 175 | return nil 176 | } 177 | 178 | //Py_GetVersion : https://docs.python.org/3/c-api/init.html#c.Py_GetVersion 179 | func Py_GetVersion() string { 180 | cversion := C.Py_GetVersion() 181 | return C.GoString(cversion) 182 | } 183 | 184 | //Py_GetPlatform : https://docs.python.org/3/c-api/init.html#c.Py_GetPlatform 185 | func Py_GetPlatform() string { 186 | cplatform := C.Py_GetPlatform() 187 | return C.GoString(cplatform) 188 | } 189 | 190 | //Py_GetCopyright : https://docs.python.org/3/c-api/init.html#c.Py_GetCopyright 191 | func Py_GetCopyright() string { 192 | ccopyright := C.Py_GetCopyright() 193 | return C.GoString(ccopyright) 194 | } 195 | 196 | //Py_GetCompiler : https://docs.python.org/3/c-api/init.html#c.Py_GetCompiler 197 | func Py_GetCompiler() string { 198 | ccompiler := C.Py_GetCompiler() 199 | return C.GoString(ccompiler) 200 | } 201 | 202 | //Py_GetBuildInfo : https://docs.python.org/3/c-api/init.html#c.Py_GetBuildInfo 203 | func Py_GetBuildInfo() string { 204 | cbuildInfo := C.Py_GetBuildInfo() 205 | return C.GoString(cbuildInfo) 206 | } 207 | 208 | //PySys_SetArgvEx : https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx 209 | func PySys_SetArgvEx(args []string, updatepath bool) error { 210 | argc := C.int(len(args)) 211 | argv := make([]*C.wchar_t, argc, argc) 212 | for i, arg := range args { 213 | carg := C.CString(arg) 214 | defer C.free(unsafe.Pointer(carg)) 215 | 216 | warg := C.Py_DecodeLocale(carg, nil) 217 | if warg == nil { 218 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", arg) 219 | } 220 | // Py_DecodeLocale requires a call to PyMem_RawFree to free the memory 221 | defer C.PyMem_RawFree(unsafe.Pointer(warg)) 222 | 223 | argv[i] = warg 224 | } 225 | 226 | if updatepath { 227 | C.PySys_SetArgvEx(argc, (**C.wchar_t)(unsafe.Pointer(&argv[0])), 1) 228 | } else { 229 | C.PySys_SetArgvEx(argc, (**C.wchar_t)(unsafe.Pointer(&argv[0])), 0) 230 | } 231 | 232 | return nil 233 | } 234 | 235 | //PySys_SetArgv : https://docs.python.org/3/c-api/init.html#c.PySys_SetArgv 236 | func PySys_SetArgv(args []string) error { 237 | argc := C.int(len(args)) 238 | argv := make([]*C.wchar_t, argc, argc) 239 | for i, arg := range args { 240 | carg := C.CString(arg) 241 | defer C.free(unsafe.Pointer(carg)) 242 | 243 | warg := C.Py_DecodeLocale(carg, nil) 244 | if warg == nil { 245 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", arg) 246 | } 247 | // Py_DecodeLocale requires a call to PyMem_RawFree to free the memory 248 | defer C.PyMem_RawFree(unsafe.Pointer(warg)) 249 | 250 | argv[i] = warg 251 | } 252 | C.PySys_SetArgv(argc, (**C.wchar_t)(unsafe.Pointer(&argv[0]))) 253 | 254 | return nil 255 | } 256 | 257 | //Py_SetPythonHome : https://docs.python.org/3/c-api/init.html#c.Py_SetPythonHome 258 | func Py_SetPythonHome(home string) error { 259 | chome := C.CString(home) 260 | defer C.free(unsafe.Pointer(chome)) 261 | 262 | newHome := C.Py_DecodeLocale(chome, nil) 263 | if newHome == nil { 264 | return fmt.Errorf("fail to call Py_DecodeLocale on '%s'", home) 265 | } 266 | C.Py_SetPythonHome(newHome) 267 | 268 | C.PyMem_RawFree(unsafe.Pointer(pythonHome)) 269 | pythonHome = newHome 270 | 271 | return nil 272 | } 273 | 274 | //Py_GetPythonHome : https://docs.python.org/3/c-api/init.html#c.Py_GetPythonHome 275 | func Py_GetPythonHome() (string, error) { 276 | wchome := C.Py_GetPythonHome() 277 | if wchome == nil { 278 | return "", nil 279 | } 280 | chome := C.Py_EncodeLocale(wchome, nil) 281 | if chome == nil { 282 | return "", fmt.Errorf("fail to call Py_EncodeLocale") 283 | } 284 | defer C.PyMem_Free(unsafe.Pointer(chome)) 285 | 286 | return C.GoString(chome), nil 287 | } 288 | -------------------------------------------------------------------------------- /object.go: -------------------------------------------------------------------------------- 1 | /* 2 | Unless explicitly stated otherwise all files in this repository are licensed 3 | under the MIT License. 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | Copyright 2018 Datadog, Inc. 6 | */ 7 | 8 | package python3 9 | 10 | //go:generate go run script/variadic.go 11 | 12 | /* 13 | #include "Python.h" 14 | #include "macro.h" 15 | #include "variadic.h" 16 | */ 17 | import "C" 18 | import ( 19 | "unsafe" 20 | ) 21 | 22 | //MaxVariadicLength is the maximum number of arguments that can be passed to a variadic C function due to a cgo limitation 23 | const MaxVariadicLength = 20 24 | 25 | // Constants used for comparison in PyObject_RichCompareBool 26 | var ( 27 | Py_LT = int(C.Py_LT) 28 | Py_LE = int(C.Py_LE) 29 | Py_EQ = int(C.Py_EQ) 30 | Py_NE = int(C.Py_NE) 31 | Py_GT = int(C.Py_GT) 32 | Py_GE = int(C.Py_GE) 33 | ) 34 | 35 | //None : https://docs.python.org/3/c-api/none.html#c.Py_None 36 | var Py_None = togo(C.Py_None) 37 | 38 | //PyObject : https://docs.python.org/3/c-api/structures.html?highlight=pyobject#c.PyObject 39 | type PyObject C.PyObject 40 | 41 | //IncRef : https://docs.python.org/3/c-api/refcounting.html#c.Py_INCREF 42 | func (pyObject *PyObject) IncRef() { 43 | C.Py_IncRef(toc(pyObject)) 44 | } 45 | 46 | //DecRef : https://docs.python.org/3/c-api/refcounting.html#c.Py_DECREF 47 | func (pyObject *PyObject) DecRef() { 48 | C.Py_DecRef(toc(pyObject)) 49 | } 50 | 51 | //ReprEnter : https://docs.python.org/3/c-api/exceptions.html#c.Py_ReprEnter 52 | func (pyObject *PyObject) ReprEnter() int { 53 | return int(C.Py_ReprEnter(toc(pyObject))) 54 | } 55 | 56 | //ReprLeave : https://docs.python.org/3/c-api/exceptions.html#c.Py_ReprLeave 57 | func (pyObject *PyObject) ReprLeave() { 58 | C.Py_ReprLeave(toc(pyObject)) 59 | } 60 | 61 | //HasAttr : https://docs.python.org/3/c-api/object.html#c.PyObject_HasAttr 62 | func (pyObject *PyObject) HasAttr(attr_name *PyObject) bool { 63 | return C.PyObject_HasAttr(toc(pyObject), toc(attr_name)) == 1 64 | } 65 | 66 | //HasAttrString : https://docs.python.org/3/c-api/object.html#c.PyObject_HasAttrString 67 | func (pyObject *PyObject) HasAttrString(attr_name string) bool { 68 | cattr_name := C.CString(attr_name) 69 | defer C.free(unsafe.Pointer(cattr_name)) 70 | 71 | return C.PyObject_HasAttrString(toc(pyObject), cattr_name) == 1 72 | } 73 | 74 | //GetAttr : https://docs.python.org/3/c-api/object.html#c.PyObject_GetAttr 75 | func (pyObject *PyObject) GetAttr(attr_name *PyObject) *PyObject { 76 | return togo(C.PyObject_GetAttr(toc(pyObject), toc(attr_name))) 77 | } 78 | 79 | //GetAttrString : https://docs.python.org/3/c-api/object.html#c.PyObject_GetAttrString 80 | func (pyObject *PyObject) GetAttrString(attr_name string) *PyObject { 81 | cattr_name := C.CString(attr_name) 82 | defer C.free(unsafe.Pointer(cattr_name)) 83 | 84 | return togo(C.PyObject_GetAttrString(toc(pyObject), cattr_name)) 85 | } 86 | 87 | //SetAttr : https://docs.python.org/3/c-api/object.html#c.PyObject_SetAttr 88 | func (pyObject *PyObject) SetAttr(attr_name *PyObject, v *PyObject) int { 89 | return int(C.PyObject_SetAttr(toc(pyObject), toc(attr_name), toc(v))) 90 | } 91 | 92 | //SetAttrString : https://docs.python.org/3/c-api/object.html#c.PyObject_SetAttrString 93 | func (pyObject *PyObject) SetAttrString(attr_name string, v *PyObject) int { 94 | cattr_name := C.CString(attr_name) 95 | defer C.free(unsafe.Pointer(cattr_name)) 96 | 97 | return int(C.PyObject_SetAttrString(toc(pyObject), cattr_name, toc(v))) 98 | } 99 | 100 | //DelAttr : https://docs.python.org/3/c-api/object.html#c.PyObject_DelAttr 101 | func (pyObject *PyObject) DelAttr(attr_name *PyObject) int { 102 | return int(C._go_PyObject_DelAttr(toc(pyObject), toc(attr_name))) 103 | } 104 | 105 | //DelAttrString : https://docs.python.org/3/c-api/object.html#c.PyObject_DelAttrString 106 | func (pyObject *PyObject) DelAttrString(attr_name string) int { 107 | cattr_name := C.CString(attr_name) 108 | defer C.free(unsafe.Pointer(cattr_name)) 109 | 110 | return int(C._go_PyObject_DelAttrString(toc(pyObject), cattr_name)) 111 | } 112 | 113 | //RichCompare : https://docs.python.org/3/c-api/object.html#c.PyObject_RichCompare 114 | func (pyObject *PyObject) RichCompare(o *PyObject, opid int) *PyObject { 115 | return togo(C.PyObject_RichCompare(toc(pyObject), toc(o), C.int(opid))) 116 | } 117 | 118 | //RichCompareBool : https://docs.python.org/3/c-api/object.html#c.PyObject_RichCompareBool 119 | func (pyObject *PyObject) RichCompareBool(o *PyObject, opid int) int { 120 | return int(C.PyObject_RichCompareBool(toc(pyObject), toc(o), C.int(opid))) 121 | } 122 | 123 | //Repr : https://docs.python.org/3/c-api/object.html#c.PyObject_Repr 124 | func (pyObject *PyObject) Repr() *PyObject { 125 | return togo(C.PyObject_Repr(toc(pyObject))) 126 | } 127 | 128 | //ASCII : https://docs.python.org/3/c-api/object.html#c.PyObject_ASCII 129 | func (pyObject *PyObject) ASCII() *PyObject { 130 | return togo(C.PyObject_ASCII(toc(pyObject))) 131 | } 132 | 133 | //Str : https://docs.python.org/3/c-api/object.html#c.PyObject_Str 134 | func (pyObject *PyObject) Str() *PyObject { 135 | return togo(C.PyObject_Str(toc(pyObject))) 136 | } 137 | 138 | //Bytes : https://docs.python.org/3/c-api/object.html#c.PyObject_Bytes 139 | func (pyObject *PyObject) Bytes() *PyObject { 140 | return togo(C.PyObject_Bytes(toc(pyObject))) 141 | } 142 | 143 | //IsSubclass : https://docs.python.org/3/c-api/object.html#c.PyObject_IsSubclass 144 | func (pyObject *PyObject) IsSubclass(cls *PyObject) int { 145 | return int(C.PyObject_IsSubclass(toc(pyObject), toc(cls))) 146 | } 147 | 148 | //IsInstance : https://docs.python.org/3/c-api/object.html#c.PyObject_IsInstance 149 | func (pyObject *PyObject) IsInstance(cls *PyObject) int { 150 | return int(C.PyObject_IsInstance(toc(pyObject), toc(cls))) 151 | } 152 | 153 | // PyCallable_Check : https://docs.python.org/3/c-api/object.html#c.PyCallable_Check 154 | func PyCallable_Check(o *PyObject) bool { 155 | return C.PyCallable_Check(toc(o)) == 1 156 | } 157 | 158 | //Call : https://docs.python.org/3/c-api/object.html#c.PyObject_Call 159 | func (pyObject *PyObject) Call(args *PyObject, kwargs *PyObject) *PyObject { 160 | return togo(C.PyObject_Call(toc(pyObject), toc(args), toc(kwargs))) 161 | } 162 | 163 | //CallObject : https://docs.python.org/3/c-api/object.html#c.PyObject_CallObject 164 | func (pyObject *PyObject) CallObject(args *PyObject) *PyObject { 165 | return togo(C.PyObject_CallObject(toc(pyObject), toc(args))) 166 | } 167 | 168 | //CallFunctionObjArgs : https://docs.python.org/3/c-api/object.html#c.PyObject_CallFunctionObjArgs 169 | func (pyObject *PyObject) CallFunctionObjArgs(args ...*PyObject) *PyObject { 170 | 171 | if len(args) > MaxVariadicLength { 172 | panic("CallFunctionObjArgs: too many arrguments") 173 | } 174 | if len(args) == 0 { 175 | return togo(C._go_PyObject_CallFunctionObjArgs(toc(pyObject), 0, (**C.PyObject)(nil))) 176 | } 177 | 178 | cargs := make([]*C.PyObject, len(args), len(args)) 179 | for i, arg := range args { 180 | cargs[i] = toc(arg) 181 | } 182 | return togo(C._go_PyObject_CallFunctionObjArgs(toc(pyObject), C.int(len(args)), (**C.PyObject)(unsafe.Pointer(&cargs[0])))) 183 | } 184 | 185 | //CallMethodObjArgs : https://docs.python.org/3/c-api/object.html#c.PyObject_CallMethodObjArgs 186 | func (pyObject *PyObject) CallMethodObjArgs(name *PyObject, args ...*PyObject) *PyObject { 187 | if len(args) > MaxVariadicLength { 188 | panic("CallMethodObjArgs: too many arguments") 189 | } 190 | if len(args) == 0 { 191 | return togo(C._go_PyObject_CallMethodObjArgs(toc(pyObject), toc(name), 0, (**C.PyObject)(nil))) 192 | } 193 | 194 | cargs := make([]*C.PyObject, len(args), len(args)) 195 | for i, arg := range args { 196 | cargs[i] = toc(arg) 197 | } 198 | return togo(C._go_PyObject_CallMethodObjArgs(toc(pyObject), toc(name), C.int(len(args)), (**C.PyObject)(unsafe.Pointer(&cargs[0])))) 199 | } 200 | 201 | //CallMethodArgs : same as CallMethodObjArgs but with name as go string 202 | func (pyObject *PyObject) CallMethodArgs(name string, args ...*PyObject) *PyObject { 203 | pyName := PyUnicode_FromString(name) 204 | defer pyName.DecRef() 205 | 206 | return pyObject.CallMethodObjArgs(pyName, args...) 207 | } 208 | 209 | //Hash : https://docs.python.org/3/c-api/object.html#c.PyObject_Hash 210 | func (pyObject *PyObject) Hash() int { 211 | return int(C.PyObject_Hash(toc(pyObject))) 212 | } 213 | 214 | //HashNotImplemented : https://docs.python.org/3/c-api/object.html#c.PyObject_HashNotImplemented 215 | func (pyObject *PyObject) HashNotImplemented() int { 216 | return int(C.PyObject_HashNotImplemented(toc(pyObject))) 217 | } 218 | 219 | //IsTrue : https://docs.python.org/3/c-api/object.html#c.PyObject_IsTrue 220 | func (pyObject *PyObject) IsTrue() int { 221 | return int(C.PyObject_IsTrue(toc(pyObject))) 222 | } 223 | 224 | //Not : https://docs.python.org/3/c-api/object.html#c.PyObject_Not 225 | func (pyObject *PyObject) Not() int { 226 | return int(C.PyObject_Not(toc(pyObject))) 227 | } 228 | 229 | //Type : https://docs.python.org/3/c-api/object.html#c.PyObject_Type 230 | func (pyObject *PyObject) Type() *PyObject { 231 | return togo(C.PyObject_Type(toc(pyObject))) 232 | } 233 | 234 | //Length : https://docs.python.org/3/c-api/object.html#c.PyObject_Length 235 | func (pyObject *PyObject) Length() int { 236 | return int(C.PyObject_Length(toc(pyObject))) 237 | } 238 | 239 | //LengthHint : https://docs.python.org/3/c-api/object.html#c.PyObject_LengthHint 240 | func (pyObject *PyObject) LengthHint(pyDefault int) int { 241 | return int(C.PyObject_LengthHint(toc(pyObject), C.Py_ssize_t(pyDefault))) 242 | } 243 | 244 | //GetItem : https://docs.python.org/3/c-api/object.html#c.PyObject_GetItem 245 | func (pyObject *PyObject) GetItem(key *PyObject) *PyObject { 246 | return togo(C.PyObject_GetItem(toc(pyObject), toc(key))) 247 | } 248 | 249 | //SetItem : https://docs.python.org/3/c-api/object.html#c.PyObject_SetItem 250 | func (pyObject *PyObject) SetItem(key, v *PyObject) int { 251 | return int(C.PyObject_SetItem(toc(pyObject), toc(key), toc(v))) 252 | } 253 | 254 | //DelItem : https://docs.python.org/3/c-api/object.html#c.PyObject_DelItem 255 | func (pyObject *PyObject) DelItem(key *PyObject) int { 256 | return int(C.PyObject_DelItem(toc(pyObject), toc(key))) 257 | } 258 | 259 | //Dir : https://docs.python.org/3/c-api/object.html#c.PyObject_Dir 260 | func (pyObject *PyObject) Dir() *PyObject { 261 | return togo(C.PyObject_Dir(toc(pyObject))) 262 | } 263 | 264 | //GetIter : https://docs.python.org/3/c-api/object.html#c.PyObject_GetIter 265 | func (pyObject *PyObject) GetIter() *PyObject { 266 | return togo(C.PyObject_GetIter(toc(pyObject))) 267 | } 268 | --------------------------------------------------------------------------------