Skip to content

Commit af59adb

Browse files
committed
Initial AOT java api.
1 parent 15c965b commit af59adb

File tree

5 files changed

+204
-5
lines changed

5 files changed

+204
-5
lines changed

deps.edn

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
libpython-clj2.python.np-array
3232
libpython-clj2.require
3333
libpython-clj2.embedded
34+
libpython-clj2.java-api
3435
python.builtins
3536
python.numpy]}}
3637
:test
@@ -55,4 +56,24 @@
5556
:exec-fn deps-deploy.deps-deploy/deploy
5657
:exec-args {:installer :remote
5758
:sign-releases? true
58-
:artifact "target/libpython-clj.jar"}}}}
59+
:artifact "target/libpython-clj.jar"}}
60+
:depstar-aot
61+
{:replace-deps
62+
{com.github.seancorfield/depstar {:mvn/version "2.0.193"}}
63+
:ns-default hf.depstar
64+
:exec-fn hf.depstar/jar
65+
:exec-args {:group-id "clj-python"
66+
:artifact-id "libpython-clj"
67+
:version "2.004-aot"
68+
:sync-pom true
69+
:aot true
70+
:compile-ns [libpython-clj2.java-api]
71+
:jar "target/libpython-clj-aot.jar"}}
72+
:deploy-aot
73+
{:replace-deps {slipset/deps-deploy {:mvn/version "0.1.5"}}
74+
:exec-fn deps-deploy.deps-deploy/deploy
75+
:exec-args {:installer :remote
76+
:sign-releases? true
77+
:artifact "target/libpython-clj-aot.jar"}}
78+
79+
}}

src/libpython_clj2/java_api.clj

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
(ns libpython-clj2.java-api
2+
(:require [tech.v3.datatype :as dtype]
3+
[tech.v3.tensor :as dtt]
4+
[tech.v3.datatype.jvm-map :as jvm-map]
5+
[libpython-clj2.python :as py]
6+
[libpython-clj2.python.fn :as py-fn]
7+
;; numpy support
8+
[libpython-clj2.python.np-array])
9+
(:import [java.util Map]
10+
[java.util.function Supplier])
11+
(:gen-class
12+
:name libpython_clj2.java_api
13+
:main false
14+
:methods [#^{:static true} [initialize [java.util.Map] Object]
15+
#^{:static true} [runString [String] java.util.Map]
16+
#^{:static true} [inPyContext [java.util.function.Supplier] Object]
17+
#^{:static true} [hasAttr [Object String] Boolean]
18+
#^{:static true} [getAttr [Object String] Object]
19+
#^{:static true} [setAttr [Object String Object] Object]
20+
#^{:static true} [hasItem [Object Object] Boolean]
21+
#^{:static true} [getItem [Object Object] Object]
22+
#^{:static true} [setItem [Object Object Object] Object]
23+
#^{:static true} [importModule [String] Object]
24+
#^{:static true} [callKw [Object java.util.List java.util.Map] Object]
25+
#^{:static true} [copyToPy [Object] Object]
26+
#^{:static true} [copyToJVM [Object] Object]
27+
#^{:static true} [createArray [String Object Object] Object]
28+
#^{:static true} [arrayToJVM [Object] java.util.Map]]))
29+
30+
31+
(set! *warn-on-reflection* true)
32+
33+
34+
(defn -initialize
35+
"See options for [[libpython-clj2.python/initialize!]]. Note that the keyword
36+
option arguments can be provided by using strings so `:library-path` becomes
37+
the key \"library-path\". Also note that there is still a GIL underlying
38+
all of the further operations so java should access python via single-threaded
39+
pathways."
40+
[options]
41+
(apply py/initialize! (->> options
42+
(mapcat (fn [entry]
43+
[(keyword (jvm-map/entry-key entry))
44+
(jvm-map/entry-value entry)])))))
45+
46+
47+
(defn -runString
48+
"Run a string returning a map of two keys -\"globals\" and \"locals\" which each point to
49+
a java.util.Map of the respective contexts. See documentation under
50+
[[libpython-clj2.python/run-simple-string]] - specifically this will never return
51+
the result of the last statement ran - you need to set a value in the global or local
52+
context."
53+
^java.util.Map [^String code]
54+
(->> (py/run-simple-string code)
55+
(map (fn [[k v]]
56+
[(name k) v]))
57+
(into {})))
58+
59+
60+
(defn -inPyContext
61+
"Run some code in a python context where all python objects allocated within the context
62+
will be deallocated once the context is released. The code must not return references
63+
to live python objects."
64+
[^Supplier fn]
65+
(py/with-gil-stack-rc-context
66+
(-> (.get fn)
67+
(py/->jvm))))
68+
69+
70+
(defn -hasAttr
71+
"Returns true if this python object has this attribute."
72+
[pyobj attname]
73+
(boolean (py/has-attr? pyobj attname)))
74+
75+
76+
(defn -getAttr
77+
"Get a python attribute. This corresponds to the python '.' operator."
78+
[pyobj attname]
79+
(py/get-attr pyobj attname))
80+
81+
82+
(defn -setAttr
83+
"Set an attribute on a python object. This corresponds to the `__setattr` python call."
84+
[pyobj attname objval]
85+
(py/set-attr! pyobj attname objval))
86+
87+
88+
(defn -hasItem
89+
"Return true if this pyobj has this item"
90+
[pyobj itemName]
91+
(boolean (py/has-item? pyobj itemName)))
92+
93+
94+
(defn -getItem
95+
[pyobj itemName]
96+
(py/get-item pyobj itemName))
97+
98+
99+
(defn -getItem
100+
[pyobj itemName]
101+
(py/get-item pyobj itemName))
102+
103+
104+
(defn -setItem
105+
[pyobj itemName itemVal]
106+
(py/get-item pyobj itemName itemVal))
107+
108+
109+
(defn -importModule
110+
"Import a python module. Module entries can be accessed via `getAttr`."
111+
[modname]
112+
(py/import-module modname))
113+
114+
115+
(defn -callKw
116+
"Call a python callable with keyword arguments. Note that you don't need this pathway
117+
to call python methods if you do not need keyword arguments; if the python object is
118+
callable then it will implement `clojure.lang.IFn` and you can use `invoke`."
119+
[pyobj pos-args kw-args]
120+
(py/with-gil (py-fn/call-kw pyobj pos-args (->> kw-args
121+
(map (fn [entry]
122+
[(jvm-map/entry-key entry)
123+
(jvm-map/entry-value entry)]))
124+
(into {})))))
125+
126+
(defn -copyToPy
127+
"Copy a basic jvm object, such as an implementation of java.util.Map or java.util.List to
128+
a python object."
129+
[object]
130+
(py/->python object))
131+
132+
133+
(defn -copyToJVM
134+
"Copy a python object such as a dict or a list into a comparable JVM object."
135+
[object]
136+
(py/->jvm object))
137+
138+
139+
(defn -createArray
140+
"Create a numpy array from a tuple of string datatype, shape and data.
141+
* `datatype` - One of \"int8\" \"uint8\" "
142+
[datatype shape data]
143+
(-> (dtt/->tensor data :datatype (keyword datatype))
144+
(dtt/reshape shape)
145+
(py/->python)))
146+
147+
148+
(defn -arrayToJVM
149+
"Copy (efficiently) a numeric numpy array into a jvm map containing keys \"datatype\",
150+
\"shape\", and \"data\"."
151+
[pyobj]
152+
(let [tens-data (py/as-jvm pyobj)]
153+
{"datatype" (name (dtype/elemwise-datatype tens-data))
154+
"shape" (int-array (dtype/shape tens-data))
155+
"data" (dtype/->array tens-data)}))

src/libpython_clj2/python.clj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ user> (py/py. np linspace 2 3 :num 10)
144144

145145

146146
(defn import-module
147-
"Import a python module returning an implementation of java.util.Map wrapping
148-
the module object and consisting of module attributes."
147+
"Import a python module. Module entries can be accessed via get-attr."
149148
[modname]
150149
(with-gil
151150
(if-let [mod (py-ffi/PyImport_ImportModule modname)]

src/libpython_clj2/python/np_array.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@
139139
:uint8 "c_ubyte"
140140
:int16 "c_short"
141141
:uint16 "c_ushort"
142-
:int32 "c_long"
143-
:uint32 "c_ulong"
142+
:int32 "c_int"
143+
:uint32 "c_uint"
144144
:int64 "c_longlong"
145145
:uint64 "c_ulonglong"
146146
:float32 "c_float"

test/libpython_clj2/java_api_test.clj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(ns libpython-clj2.java-api-test
2+
(:require [libpython-clj2.java-api :as japi]
3+
[tech.v3.datatype.jvm-map :as jvm-map]
4+
[clojure.test :refer [deftest is]]))
5+
6+
7+
(deftest base-japi-test
8+
(japi/-initialize nil)
9+
(let [rs-retval (japi/-runString "data = 5")
10+
globals (get rs-retval "globals")]
11+
(is (= 5 (get globals "data"))))
12+
(let [np (japi/-importModule "numpy")
13+
ones-fn (japi/-getAttr np "ones")
14+
;;also works with int-array
15+
base-data (ones-fn (java.util.ArrayList. [2 3]))
16+
jvm-data (japi/-arrayToJVM base-data)]
17+
(is (= "float64" (get jvm-data "datatype")))
18+
(is (= (vec (repeat 6 1.0))
19+
(vec (get jvm-data "data"))))
20+
(let [base-data (japi/-callKw ones-fn [[2 3]] {"dtype" "int32"})
21+
jvm-data (japi/-arrayToJVM base-data)]
22+
(is (= "int32" (get jvm-data "datatype")))
23+
(is (= (vec (repeat 6 1))
24+
(vec (get jvm-data "data")))))))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy