Skip to content

Commit

Permalink
make require-python optionally user path informed (#254)
Browse files Browse the repository at this point in the history
Co-authored-by: James J. Tolton <jay@toltontechnology.ai>
  • Loading branch information
jjtolton and James J. Tolton authored Oct 15, 2023
1 parent 67b83cc commit b25f366
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 10 deletions.
7 changes: 7 additions & 0 deletions src/libpython_clj2/metadata.clj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
(get-attr % "__doc__")
(catch Exception e
"")))
(def os (import-module "os"))
(def get-pydoc doc)
(def vars (get-attr builtins "vars"))
(def pyclass? (get-attr inspect "isclass"))
Expand Down Expand Up @@ -227,6 +228,12 @@
(or (string? att-val)
(number? att-val)))

(defn py-chdir [path]
(py/$a os "chdir" path))

(defn py-getcwd []
(py/$a os "getcwd"))

(defn datafy-module-or-class [item]
(with-gil
(->> (if (or (pyclass? item)
Expand Down
107 changes: 97 additions & 10 deletions src/libpython_clj2/require.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
[libpython-clj2.metadata :as pymeta]
[clojure.datafy :refer [datafy nav]]
[clojure.tools.logging :as log]
[clojure.core.protocols :as clj-proto]))
[clojure.core.protocols :as clj-proto])
(:import (java.io File)))


(defn- parse-flags
Expand All @@ -19,7 +20,7 @@
;; First attempt is to filter keywords and make sure any keywords are
;; in supported-flags
(let [total-flags (set (concat supported-flags [:as :refer :exclude
:* :all :bind-ns]))]
:* :all :bind-ns :path]))]
(when-let [missing-flags (->> reqs
(filter #(and (not (total-flags %))
(keyword? %)))
Expand Down Expand Up @@ -100,13 +101,20 @@
no-arglists? (:no-arglists flags)
bind-ns? (:bind-ns flags)
alias-name (:as etc)
path (:path etc)
exclude (into #{} (:exclude etc))

refer-data (cond
(= :all (:refer etc)) #{:all}
(= :* (:refer etc)) #{:*}
:else (into #{} (:refer etc)))
pyobj (py/path->py-obj (str module-name) :reload? reload?)
pyobj (if path
(let [cwd (pymeta/py-getcwd)]
(try
(pymeta/py-chdir path)
(py/path->py-obj (str module-name) :reload? reload?)
(finally
(pymeta/py-chdir cwd))))
(py/path->py-obj (str module-name) :reload? reload?))
existing-py-ns? (find-ns module-name)]
(create-ns module-name)

Expand Down Expand Up @@ -170,6 +178,7 @@
(into [(req-transform prefix base)] reqs))))))



(defn require-python
"## Basic usage ##
Expand Down Expand Up @@ -219,9 +228,64 @@
## Setting up classpath for custom modules ##
Note: you may need to setup your PYTHONPATH correctly.
One technique to do this is, if your foo.py lives at
/path/to/foodir/foo.py:
**WARNING**: This is very handy for local REPL development,
..: if you are going to AOT classes,
..: refer to the documentation on codegen
..: or your AOT compilation will fail.
If your foo.py lives at /path/to/foodir/foo.py, the easiest
way to do it is:
(require-python :from \"/path/to/foodir\"
'foo) ;; or
(require-python \"/path/to/foodir\"
'foo) ;; or
(require-python {:from \"/path/to/foodir\"}
'foo)
as you prefer.
Additionally, if you want to keep the namespacing as you have
it in Python, you may prefer to use a relative import
starting from a location of your choosing. If your
os.getcwd() => /some/path/foo,
and your directory structure looks something like:
/some $ tree
.
└── path
├── baz
│ └── quux.py
└── foo
└── bar.py
(require-python :from \"path\"
'[baz.quux :as quux]
:from \"path/foo\"
'bar)
is perfectly acceptable. It probably makes the most
sense to keep you style consistent, but you can mix
and match as you see fit between <path>, :from <path>,
and {:from <path>}. <path> can either be a file or a
directory. If it is a file, the Python path will be
set to the directory containing that file.
You may also stack several require-pythons under one path:
(require-python {:from \"dir-a\"}
'a
'b
'c
{:from \"dir-b\"}
'e.f
'g
{:from \"dir-c}
'hi.there)
Other options more in keeping with traditional PYTHONPATH
management include:
(require-python 'sys)
(py/call-attr (py/get-attr sys \"path\")
\"append\"
Expand Down Expand Up @@ -275,9 +339,32 @@
(throw (Exception. "Invalid argument: %s" req))))
:ok)
([req & reqs]
(require-python req)
(when (not-empty reqs)
(apply require-python reqs))
(cond (and (map? req)
(contains? req :from)
(seq reqs))
(apply require-python (:from req) reqs)
(and (keyword? req)
(= :from req)
(string? (first reqs)))
(apply require-python (first reqs) (rest reqs))
(and (string? req)
(.isFile (File. req)))
(let [file (File. req)
cwd (pymeta/py-getcwd)]
(apply require-python (str (.getParent file)) reqs))
(and (string? req)
(.isDirectory (File. req)))
(let [cwd (pymeta/py-getcwd)]
(try
(pymeta/py-chdir req)
(apply require-python reqs)
(finally
(pymeta/py-chdir cwd))))
:else
(do
(require-python req)
(when (not-empty reqs)
(apply require-python reqs))))
:ok))


Expand Down

0 comments on commit b25f366

Please sign in to comment.