clj-python / libpython-clj

Python bindings for Clojure
Eclipse Public License 2.0
1.08k stars 68 forks source link

Get Class Information As Data #158

Closed zachcp closed 3 years ago

zachcp commented 3 years ago

Chris,

This is an awesome library, thank you. I am exploring the python->clojure conversions and notice that ->jvm returns pointers when encountering objects. Is there a way to convert all classes/fields to clojure as below?

zach cp

; test example. 
(let [c1   (py/create-class "TestClass1" "" {:a 1 :b 2 :c []})
      c2   (py/create-class "TestClass2" "" {:a 1 :b 2})]
  (py/set-attr! c1 :c c2)
  (py/->jvm c1))

; yields
{:type :type
 :value #object[tech.v3.datatype.ffi.Pointer 0x3e70fbd4 "{:address 0x00007FC6D47EEB60 }"]}

; desired
{:type :TestClass1
 :a 1
 :b 2
 :c {:type :TestClass2
     :a 1
     :b 2}}
cnuernber commented 3 years ago

Not via a pure library call there isn't but you could do this with a recursive combination of dir and get-attr. The desire makes sense for sure and perhaps a datafy pathway could be done. The metadata module does something similar but it gets the metadata on the attributes in addition to their values so you get documentation on member functions and such.

zachcp commented 3 years ago

Thanks Chris. I'll take a look at the metadata module. I also see that I can extend the ->jvm method on a per-class basis.

; I also tried manually extending ->jvm on a per-class basis
(defmethod py-proto/pyobject->jvm :type [pyobj & args]
  {:a (py/->jvm (py/get-attr pyobj :a))
   :b (py/->jvm (py/get-attr pyobj :b))
   :c (py/->jvm (py/get-attr pyobj :c))
   :type :TestClass})

(let [c1       (py/create-class "TestClass1" "" {:a 1 :b 2 :c []})
      c2       (py/create-class "TestClass2" "" {:a 1 :b 2 :c []})]
  (py/set-attr! c1 :c c2)
  (py/->jvm c1))

{:type :TestClass
 :a 1 
 :b 2
 :c { :type :TestClass
       :a 1
       :b 2
       :c []}}
jjtolton commented 3 years ago

I would also add that we implement datafy, so you could extend the datafy method we have to include the classes you are interested in.

On Mon, May 10, 2021 at 12:36 PM zachcp @.***> wrote:

Thanks Chris. I'll take a look at the metadata module. I also see that I can extend the ->jvm method on a per-class basis.

; I also tried manually extending ->jvm on a per-class basis (defmethod py-proto/pyobject->jvm :type [pyobj & args] {:a (py/->jvm (py/get-attr pyobj :a)) :b (py/->jvm (py/get-attr pyobj :b)) :c (py/->jvm (py/get-attr pyobj :c)) :type :TestClass})

(let [c1 (py/create-class "TestClass1" "" {:a 1 :b 2 :c []}) c2 (py/create-class "TestClass2" "" {:a 1 :b 2 :c []})] (py/set-attr! c1 :c c2) (py/->jvm c1))

{:type :TestClass

:a 1 :b 2 :c { :type :TestClass :a 1 :b 2 :c []}}

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/clj-python/libpython-clj/issues/158#issuecomment-836934664, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACPJX45SUUIHARBZVI55WXLTNADQ3ANCNFSM43VLRIXA .