-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathpython.go
More file actions
137 lines (112 loc) · 3.25 KB
/
python.go
File metadata and controls
137 lines (112 loc) · 3.25 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
129
130
131
132
133
134
135
136
137
package py
// #cgo CFLAGS: -Werror
// #cgo pkg-config: python-3.14-embed libffi
//
// #include "utils.h"
import "C"
import (
"log"
"unsafe"
)
// Code generation commands:
//go:generate ./gen_exc.py exc.go python3.14
//go:generate ./gen_slots.py
//go:generate ./gen_types.py python3.14
//go:generate ./gen_arg.py
// nilValue is the value returned from String methods when the value is nil.
const nilValue = "<nil>"
// 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 cfree(p)
sysPath := C.PySys_GetObject(p)
if sysPath == nil {
return AttributeError.Err("path")
}
s := C.CString(dir)
defer cfree(s)
pDir := C.PyUnicode_FromString(s)
if pDir == nil {
return exception()
}
defer decref(pDir)
return int2Err(C.PyList_Append(sysPath, pDir))
}
// PrependToPath prepends the given directory to sys.path.
func PrependToPath(dir string) error {
p := C.CString("path")
defer cfree(p)
sysPath := C.PySys_GetObject(p)
if sysPath == nil {
return AttributeError.Err("path")
}
s := C.CString(dir)
defer cfree(s)
pDir := C.PyUnicode_FromString(s)
if pDir == nil {
return exception()
}
defer decref(pDir)
return int2Err(C.PyList_Insert(sysPath, 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 cfree(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 cfree(s)
return C.enterRecursive(s) == 0
}
// LeaveRecursiveCall must be called after a recursive call that was indicated
// by EnterRecursiveCall.
func LeaveRecursiveCall() {
C.leaveRecursive()
}
func cfree[T any](value *T) {
C.free(unsafe.Pointer(value))
}