forked from clj-python/libpython-clj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpython.clj
100 lines (74 loc) · 2.85 KB
/
python.clj
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
(ns libpython-clj.python
(:require [libpython-clj.jna :as libpy]
[tech.jna.base :as jna-base]
[tech.jna :as jna]
[tech.resource :as resource]
[tech.resource.gc :as resource-gc]
[tech.parallel.require :as parallel-req])
(:import [tech.resource GCSoftReference]
[com.sun.jna Pointer]
[com.sun.jna.ptr PointerByReference]
[java.lang AutoCloseable]))
(set! *warn-on-reflection* true)
(defonce taoensso-logger
(future {:info (parallel-req/require-resolve 'tech.jna.timbre-log/log-info)
:warn (parallel-req/require-resolve 'tech.jna.timbre-log/log-warn)
:error (parallel-req/require-resolve 'tech.jna.timbre-log/log-error)
}))
(defn log-level
[level msg]
(if-let [logger (try (get @taoensso-logger level)
(catch Throwable e nil))]
(logger msg)
(println (format "%s: %s" (name level) msg))))
(defn log-error
[log-str]
(log-level :error log-str))
(defn log-info
[log-str]
(log-level :info log-str))
(defn logthrow-error
[log-str & [data]]
(throw (ex-info log-str data)))
(defrecord LibPython []
AutoCloseable
(close [this]
))
(defonce ^:dynamic *python* (atom nil))
(defn wide-str-ptr
^Pointer [^String data]
(let [^Pointer retval (jna/malloc (+ 2 (count data)))]
(.setString retval 0 data "UTF-16")
retval))
(defn ->ptr-ptr
^PointerByReference [^Pointer value]
(PointerByReference. value))
(def ^:dynamic *program-name* nil)
(defn get-instance
"Instance is guaranteed to be alive as long as caller has a gc reference to it"
[& [^String program-name]]
(if-let [retval (when-let [^GCSoftReference refdata @*python*]
(.get refdata))]
retval
(locking *python*
(log-info "Creating python libary bindings")
(let [retval (do ;; Disable signals
(libpy/Py_InitializeEx 0)
;;Set program name
(when-let [program-name (or program-name *program-name*)]
(resource/stack-resource-context
(libpy/PySys_SetArgv 0 (-> program-name
(wide-str-ptr)
(->ptr-ptr)))))
(->LibPython))]
(reset! *python* (resource-gc/soft-reference
retval
#(do
(log-info "Destroying python libary bindings")
(let [finalize-val (long (libpy/Py_FinalizeEx))]
(when-not (= 0 finalize-val)
(log-error (format "Py_Finalize failure: %s" finalize-val)))))))
retval))))
(defn wrap-pyobject
[pyobj]
(resource/track pyobj (partial libpy/Py_DecRef (jna/as-ptr pyobj)) [:gc]))