Skip to content

Commit a85be74

Browse files
authored
add pathing metadata; fix metatype bug (#118)
1 parent a846a49 commit a85be74

3 files changed

Lines changed: 70 additions & 19 deletions

File tree

src/libpython_clj/metadata.clj

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
(def inspect (as-jvm (import-module "inspect") {}))
1818
(def argspec (get-attr inspect "getfullargspec"))
1919
(def py-source (get-attr inspect "getsource"))
20+
(def py-sourcelines (get-attr inspect "getsourcelines"))
21+
(def py-file (get-attr inspect "getfile"))
2022
(def types (import-module "types"))
2123
(def fn-type
2224
(call-attr builtins "tuple"
@@ -42,11 +44,25 @@
4244
(def importlib (py/import-module "importlib"))
4345
(def importlib_util (import-module "importlib.util"))
4446
(def reload-module (py/get-attr importlib "reload"))
47+
4548
(defn findspec [x]
4649
(let [-findspec
4750
(-> importlib_util (get-attr "find_spec"))]
4851
(-findspec x)))
4952

53+
54+
(defn find-lineno [x]
55+
(try
56+
(-> x py-sourcelines last)
57+
(catch Exception _
58+
nil)))
59+
60+
(defn find-file [x]
61+
(try
62+
(py-file x)
63+
(catch Exception _
64+
nil)))
65+
5066
(defn py-fn-argspec [f]
5167
(if-let [spec (try (when-not (pyclass? f)
5268
(argspec f))
@@ -155,10 +171,6 @@
155171
(recur argspec' defaults' arglists))))))
156172

157173

158-
(defn py-class-argspec [class]
159-
(let [constructor (py/get-attr class "__init__")]
160-
(py-fn-argspec constructor)))
161-
162174

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

191203
(defn base-pyobj-map
192204
[item]
193-
(merge {:type (py/python-type item)
194-
:doc (doc item)
195-
:str (.toString item)
196-
:flags (pyobj-flags item)}
197-
(when (has-attr? item "__module__")
198-
{:module (get-attr item "__module__")})
199-
(when (has-attr? item "__name__")
200-
{:name (get-attr item "__name__")})))
205+
(cond-> {:type (py/python-type item)
206+
:doc (doc item)
207+
:str (.toString item)
208+
:flags (pyobj-flags item)
209+
:line (find-lineno item)
210+
:file (find-file item)}
211+
(has-attr? item "__module__")
212+
(assoc :module (get-attr item "__module__"))
213+
(has-attr? item "__name__")
214+
(assoc :name (get-attr item "__name__"))
215+
(and (find-lineno item) (find-file item))
216+
(assoc :line (find-lineno item) :file (find-file item))))
201217

202218

203219
(defn scalar?
@@ -280,10 +296,15 @@
280296

281297
(defn metadata-map->py-obj
282298
[metadata-map]
283-
(case (:type metadata-map)
284-
:module (import-module (:name metadata-map))
285-
:type (-> (import-module (:module metadata-map))
286-
(get-attr (:name metadata-map)))))
299+
(try
300+
(case (:type metadata-map)
301+
:module (import-module (:name metadata-map))
302+
:type (-> (import-module (:module metadata-map))
303+
(get-attr (:name metadata-map))))
304+
(catch Exception _
305+
;; metatypes -- e.g. socket.SocketIO
306+
(-> (import-module (:module metadata-map))
307+
(get-attr (:name metadata-map))))))
287308

288309

289310
(defn get-or-create-namespace!

src/libpython_clj/require.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@
127127
" to something without periods."))))
128128
(intern
129129
(symbol (str *ns*))
130-
(symbol import-name)
130+
(with-meta (symbol import-name)
131+
{:file (metadata/find-file pyobj)
132+
:line 1})
131133
pyobj)))
132134

133135
(when (or (not existing-py-ns?) reload?)

test/libpython_clj/require_python_test.clj

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,35 @@
114114

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

117-
118-
119117
(deftest import-python-test
120118
(is (= :ok (libpython-clj.require/import-python))))
119+
120+
(require-python '[socket :bind-ns true])
121+
(require-python 'socket.SocketIO)
122+
(deftest metadata-test
123+
(testing "metadata generation"
124+
;; module meta
125+
(let [{line :line file :file} (meta #'socket)]
126+
(is (= 1 line)
127+
"Modules have line numbers")
128+
(is (string? file)
129+
"Modules have file paths"))
130+
;; class meta
131+
(let [{line :line file :file} (meta #'socket/SocketIO)]
132+
(is (int? line)
133+
"Classes have line numbers")
134+
(is (string? file)
135+
"Classes have file paths"))
136+
;; function meta
137+
(let [{line :line file :file} (meta #'socket/_intenum_converter)]
138+
(is (int? line)
139+
"Functions have line numbers")
140+
(is (string? file)
141+
"Functions have file paths"))
142+
;; method meta
143+
(let [{line :line file :file} (meta #'socket.SocketIO/readable)]
144+
(is (int? line)
145+
"Methods have line numbers")
146+
(is (string? file)
147+
"Methods have file paths"))))
148+

0 commit comments

Comments
 (0)