Skip to content
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
53 changes: 37 additions & 16 deletions src/libpython_clj/metadata.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
(def inspect (as-jvm (import-module "inspect") {}))
(def argspec (get-attr inspect "getfullargspec"))
(def py-source (get-attr inspect "getsource"))
(def py-sourcelines (get-attr inspect "getsourcelines"))
(def py-file (get-attr inspect "getfile"))
(def types (import-module "types"))
(def fn-type
(call-attr builtins "tuple"
Expand All @@ -42,11 +44,25 @@
(def importlib (py/import-module "importlib"))
(def importlib_util (import-module "importlib.util"))
(def reload-module (py/get-attr importlib "reload"))

(defn findspec [x]
(let [-findspec
(-> importlib_util (get-attr "find_spec"))]
(-findspec x)))


(defn find-lineno [x]
(try
(-> x py-sourcelines last)
(catch Exception _
nil)))

(defn find-file [x]
(try
(py-file x)
(catch Exception _
nil)))

(defn py-fn-argspec [f]
(if-let [spec (try (when-not (pyclass? f)
(argspec f))
Expand Down Expand Up @@ -155,10 +171,6 @@
(recur argspec' defaults' arglists))))))


(defn py-class-argspec [class]
(let [constructor (py/get-attr class "__init__")]
(py-fn-argspec constructor)))

Comment thread
jjtolton marked this conversation as resolved.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function was defined (the same way) twice for some reason, so I removed the later one.


(defn py-fn-metadata [fn-name x {:keys [no-arglists?]}]
(let [fn-argspec (pyargspec x)
Expand Down Expand Up @@ -190,14 +202,18 @@

(defn base-pyobj-map
[item]
(merge {:type (py/python-type item)
:doc (doc item)
:str (.toString item)
:flags (pyobj-flags item)}
(when (has-attr? item "__module__")
{:module (get-attr item "__module__")})
(when (has-attr? item "__name__")
{:name (get-attr item "__name__")})))
(cond-> {:type (py/python-type item)
:doc (doc item)
:str (.toString item)
:flags (pyobj-flags item)
:line (find-lineno item)
:file (find-file item)}
(has-attr? item "__module__")
(assoc :module (get-attr item "__module__"))
(has-attr? item "__name__")
(assoc :name (get-attr item "__name__"))
(and (find-lineno item) (find-file item))
(assoc :line (find-lineno item) :file (find-file item))))


(defn scalar?
Expand Down Expand Up @@ -280,10 +296,15 @@

(defn metadata-map->py-obj
[metadata-map]
(case (:type metadata-map)
:module (import-module (:name metadata-map))
:type (-> (import-module (:module metadata-map))
(get-attr (:name metadata-map)))))
(try
(case (:type metadata-map)
:module (import-module (:name metadata-map))
:type (-> (import-module (:module metadata-map))
(get-attr (:name metadata-map))))
(catch Exception _
;; metatypes -- e.g. socket.SocketIO
(-> (import-module (:module metadata-map))
(get-attr (:name metadata-map))))))


(defn get-or-create-namespace!
Expand Down
4 changes: 3 additions & 1 deletion src/libpython_clj/require.clj
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@
" to something without periods."))))
(intern
(symbol (str *ns*))
(symbol import-name)
(with-meta (symbol import-name)
{:file (metadata/find-file pyobj)
:line 1})
pyobj)))

(when (or (not existing-py-ns?) reload?)
Expand Down
32 changes: 30 additions & 2 deletions test/libpython_clj/require_python_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,35 @@

(is (set? (datafy (python/frozenset [1 2 3])))))



(deftest import-python-test
(is (= :ok (libpython-clj.require/import-python))))

(require-python '[socket :bind-ns true])
(require-python 'socket.SocketIO)
(deftest metadata-test
(testing "metadata generation"
;; module meta
(let [{line :line file :file} (meta #'socket)]
(is (= 1 line)
"Modules have line numbers")
(is (string? file)
"Modules have file paths"))
;; class meta
(let [{line :line file :file} (meta #'socket/SocketIO)]
(is (int? line)
"Classes have line numbers")
(is (string? file)
"Classes have file paths"))
;; function meta
(let [{line :line file :file} (meta #'socket/_intenum_converter)]
(is (int? line)
"Functions have line numbers")
(is (string? file)
"Functions have file paths"))
;; method meta
(let [{line :line file :file} (meta #'socket.SocketIO/readable)]
(is (int? line)
"Methods have line numbers")
(is (string? file)
"Methods have file paths"))))