Skip to content

Added support for anaconda python under windows #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion docs/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ user> (require '[libpython-clj.python
python-type]])
nil


; Mac and Linux
user> (initialize!)
Jun 30, 2019 4:47:39 PM clojure.tools.logging$eval7369$fn__7372 invoke
INFO: executing python initialize!
Expand All @@ -53,6 +53,17 @@ INFO: Library python3.6m found at [:system "python3.6m"]
Jun 30, 2019 4:47:39 PM clojure.tools.logging$eval7369$fn__7372 invoke
INFO: Reference thread starting
:ok

; Windows with Anaconda
(initialize! ; Python executable
:python-executable "C:\\Users\\USER\\AppData\\Local\\Continuum\\anaconda3\\python.exe"
; Python Library
:library-path "C:\\Users\\USER\\AppData\\Local\\Continuum\\anaconda3\\python37.dll"
; Anacondas PATH environment to load native dlls of modules (numpy, etc.)
:windows-anaconda-activate-bat "C:\\Users\\USER\\AppData\\Local\\Continuum\\anaconda3\\Scripts\\activate.bat"
)
...
:ok
```

This dynamically finds the python shared library and loads it using output from
Expand Down
10 changes: 7 additions & 3 deletions src/libpython_clj/python.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[libpython-clj.python.interpreter :as pyinterp]
[libpython-clj.python.object :as pyobj]
[libpython-clj.python.bridge :as pybridge]
[libpython-clj.python.windows :as win]
[libpython-clj.jna :as libpy]
;;Protocol implementations purely for nd-ness
[libpython-clj.python.np-array]
Expand Down Expand Up @@ -235,7 +236,8 @@
library-path
python-home
no-io-redirect?
python-executable]}]
python-executable
windows-anaconda-activate-bat]}]
(when-not @pyinterp/main-interpreter*
(pyinterp/initialize! :program-name program-name
:library-path library-path
Expand All @@ -245,14 +247,16 @@
(pyinterop/register-bridge-type!)
(when-not no-io-redirect?
(pyinterop/setup-std-writer #'*err* "stderr")
(pyinterop/setup-std-writer #'*out* "stdout")))
(pyinterop/setup-std-writer #'*out* "stdout"))
(if-not (nil? windows-anaconda-activate-bat)
(win/setup-windows-conda! windows-anaconda-activate-bat)))
:ok)


(defn ptr-refcnt
[item]
(-> (libpy/as-pyobj item)
(libpython_clj.jna.PyObject. )
(libpython_clj.jna.PyObject.)
(.ob_refcnt)))


Expand Down
28 changes: 14 additions & 14 deletions src/libpython_clj/python/interpreter.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(ns libpython-clj.python.interpreter
(:require [libpython-clj.jna :as libpy ]
(:require [libpython-clj.jna :as libpy]
[libpython-clj.jna.base :as libpy-base]
[libpython-clj.python.gc :as pygc]
[libpython-clj.python.logging
Expand Down Expand Up @@ -30,13 +30,13 @@
(let [{:keys [out err exit]}
(sh executable "-c" "import sys, json;
print(json.dumps(
{\"platform\": sys.platform,
\"prefix\": sys.prefix,
\"base_prefix\": sys.base_prefix,
\"executable\": sys.executable,
\"base_exec_prefix\": sys.base_exec_prefix,
\"exec_prefix\": sys.exec_prefix,
\"version\": list(sys.version_info)[:3]}))")]
{'platform': sys.platform,
'prefix': sys.prefix,
'base_prefix': sys.base_prefix,
'executable': sys.executable,
'base_exec_prefix': sys.base_exec_prefix,
'exec_prefix': sys.exec_prefix,
'version': list(sys.version_info)[:3]}))")]
(when (= 0 exit)
(json/read-str out :key-fn keyword))))

Expand Down Expand Up @@ -93,7 +93,7 @@ print(json.dumps(
;; ..: mac and windows are for sys.platform
:linux "libpython%s.%sm.so$"
:mac "libpython%s.%sm.dylib$"
:windows "python%s.%sm.dll$")
:win32 "python%s%s.dll$")
major minor))))

(defn python-library-paths
Expand Down Expand Up @@ -131,9 +131,9 @@ print(json.dumps(
(let [executable "python3.7"
system-info (python-system-info executable)
pyregex (python-library-regex system-info)]
(python-library-paths system-info pyregex))
(python-library-paths system-info pyregex)))
;;=> ["/usr/lib/x86_64-linux-gnu/libpython3.7m.so" "/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so"]
)


(defn- ignore-shell-errors
[& args]
Expand Down Expand Up @@ -179,8 +179,8 @@ print(json.dumps(
;;get the type of that item if we have seen it before.
(defrecord Interpreter [
interpreter-state* ;;Thread state, per interpreter
shared-state* ;;state shared among all interpreters
])
shared-state*]) ;;state shared among all interpreters



;; Main interpreter booted up during initialize!
Expand Down Expand Up @@ -411,7 +411,7 @@ print(json.dumps(
python-executable]
:as options}]
(when-not (main-interpreter)
(log-info (str "Executing python initialize with options:" options) )
(log-info (str "Executing python initialize with options:" options))
(let [{:keys [python-home libname java-library-path-addendum] :as startup-info}
(detect-startup-info options)
library-names (cond
Expand Down
43 changes: 43 additions & 0 deletions src/libpython_clj/python/windows.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
(ns libpython-clj.python.windows
(:require [libpython-clj.python.interop :refer [run-simple-string]]
[clojure.java.shell :refer [sh]]
[clojure.java.io :as io]
[clojure.string :as s]))

(defn create-echo-path-bat! []
"Creates temporary file to extract condas PATH environment variable"
(let [tmp (java.io.File/createTempFile "echo-path" ".bat")]
(spit tmp "echo %PATH%")
(.toString tmp)))

(defn delete-echo-path-bat! [tmp]
"Deletes temporary file"
(io/delete-file tmp))

(defn- get-windows-anaconda-env-path [activate-bat echo-bat]
"Get anacondas windows PATH environment variable to load native dlls for numpy etc. like python with anaconda does."
(-> (sh "cmd.exe" "/K" (str activate-bat " & " echo-bat))
:out
(s/split #"\r\n")
reverse
(nth 2)))


(defn- generate-python-set-env-path [path]
"Double quote windows path separator \\ -> \\\\"
(let [quoted (s/replace path "\\" "\\\\")]
(str
"import os;\n"
"path = '" quoted "';\n"
"os.environ['PATH'] = path;\n")))

(defn setup-windows-conda! [windows-conda-activate-bat]
"Setup python PATH environment variable like in anaconda to be able to load native dlls for numpy etc. like anaconda does."
(let [echo-bat (create-echo-path-bat!)]
(->> (get-windows-anaconda-env-path
windows-conda-activate-bat
echo-bat)
generate-python-set-env-path
run-simple-string)
(delete-echo-path-bat! echo-bat)))