-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathpython.go
More file actions
128 lines (106 loc) · 3.17 KB
/
python.go
File metadata and controls
128 lines (106 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package py
// #cgo CFLAGS: -Werror
// #cgo pkg-config: python-3.13-embed libffi
//
// #include "utils.h"
import "C"
import (
"log"
"unsafe"
)
// Code generation commands:
//go:generate ./gen_exc.py exc.go python3.13
//go:generate ./gen_slots.py
//go:generate ./gen_types.py python3.13
// Initialize initialises the Python runtime.
//
// You probably want InitAndLockWithSignals though, as it doesn't require the
// caller to worry about goroutines or threads.
func Initialize() {
InitializeEx(true)
}
// InitializeEx initialises the Python runtime.
//
// If initsigs is true then the Python runtime will install signal handlers.
//
// You probably want InitAndLock or InitAndLockWithSignals though, as they
// doesn't require the caller to worry about goroutines or threads.
func InitializeEx(initsigs bool) {
if initsigs {
C.Py_InitializeEx(1)
} else {
C.Py_InitializeEx(0)
}
if err := setupImporter(); err != nil {
log.Printf("failed to setup importer: %s", err)
}
}
// Finalize shuts down the Python runtime.
//
// You probably want to call the Lock.Finalize method though, as it will ensure
// that goroutines and threads are managed correctly.
func Finalize() {
C.Py_Finalize()
}
// AddToPath appends the given directory to sys.path
func AddToPath(dir string) error {
p := C.CString("path")
defer C.free(unsafe.Pointer(p))
sys_path := C.PySys_GetObject(p)
if sys_path == nil {
return AttributeError.Err("path")
}
s := C.CString(dir)
defer C.free(unsafe.Pointer(s))
pDir := C.PyUnicode_FromString(s)
if pDir == nil {
return exception()
}
defer C.decref(pDir)
return int2Err(C.PyList_Append(sys_path, pDir))
}
// PrependToPath prepends the given directory to sys.path
func PrependToPath(dir string) error {
p := C.CString("path")
defer C.free(unsafe.Pointer(p))
sys_path := C.PySys_GetObject(p)
if sys_path == nil {
return AttributeError.Err("path")
}
s := C.CString(dir)
defer C.free(unsafe.Pointer(s))
pDir := C.PyUnicode_FromString(s)
if pDir == nil {
return exception()
}
defer C.decref(pDir)
return int2Err(C.PyList_Insert(sys_path, 0, pDir))
}
// Main is the main Python interpreter entrypoint.
//
// Once this function returns, the Python runtime is shutdown.
func Main(args []string) int {
argv := make([]*C.char, len(args))
for i, arg := range args {
argv[i] = C.CString(arg)
defer C.free(unsafe.Pointer(argv[i]))
}
return int(C.Py_BytesMain(C.int(len(argv)), &argv[0]))
}
// EnterRecursiveCall marks a point where a recursive Go-level call is about to
// be performed. It returns true if the recursive call is permitted, otherwise
// a Python exception is set and false is returned. where is a string that will
// be appended to the RuntimeError set if the recursion limit has been exceeded
// (e.g. " in instance check"). This function needs to be called if the
// recursive function may not invoke Python code (which automatically tracks
// recursion depth).
func EnterRecursiveCall(where string) bool {
s := C.CString(where)
defer C.free(unsafe.Pointer(s))
return C.enterRecursive(s) == 0
}
// LeaveRecursiveCall must be called after a recursive call that was indicated
// by EnterRecursiveCall.
func LeaveRecursiveCall() {
C.leaveRecursive()
}