Willem,
Thanks a lot. Your examples worked, and using them, I wrote a set of functions that seem to do what I want. I'll include them below, but first, here's a demo.
The python file, called /projects/shapiro/clpython/test.py ----------------------------- # A Python file to use to test clpython
def test(): print "I am a Python function." return "I am done."
def pyplus(x,y): return x+y
def pyminus(x,y): return x-y
print("The Python test file has been run.") -----------------------------
My use of it, after loading CLPython and my new utility: ----------------------------- cl-user(3): :pwd Lisp's current working directory is "/home/csefaculty/shapiro/" *default-pathname-defaults* is #P"/home/csefaculty/shapiro/"
cl-user(4): (clpython:pypaths "/projects/shapiro/clpython/") ("/projects/shapiro/clpython/")
cl-user(5): (clpython:pyimport 'test) ; Fast loading /projects/shapiro/clpython/test.fasl The Python test file has been run. #<module `test' Src: /net/projects/shapiro/clpython/test.py Binary: /net/projects/shapiro/clpython/test.fasl @ #x723d675a>
cl-user(6): (* (clpython:pycall 'test 'pyplus 3 5) (clpython:pycall 'test 'pyminus 7 4)) 24 -----------------------------
My utility. It could probably be made more sophisticated. ----------------------------- ;;; Utility for calling Python Functions from Common Lisp ;;; Stuart C. Shapiro ;;; Uses CLPython ;;; and additional suggestions from Willem Broekema ;;; January 9, 2009
(in-package :clpython)
(export '(pypaths pyimport pycall))
(setf *habitat* (make-habitat))
(defvar *pymodules* (make-hash-table) "A map from module names to module structures.")
(defun pypaths (&rest paths) "Adds the paths to the list of paths that are tried when locating a module in order to import it." (setf cl-user::*clpython-module-search-paths* (append cl-user::*clpython-module-search-paths* paths)))
(defun pyimport (module) ;; Imports the given Python module, and creates an entry for it in *pymodules*" (setf (gethash module *pymodules*) (py-import (list module))))
(defun pycall (module fn &rest args) "Calls the function named fn of the module named module on the given arguments, and returns what it returns." (unless (gethash module *pymodules*) (error "There is no loaded module named ~S." module)) (apply (attr (gethash module *pymodules*) fn) args)) -----------------------------
Thanks, again.
stu
Willem Broekema wrote:
Hello Stuart, welcome to the list.
On Thu, Jan 8, 2009 at 4:56 PM, Stuart C. Shapiro shapiro@cse.buffalo.edu wrote:
cl-user(3): (clpython:run "import test; test.test()") Warning: *import-recompiled-files* = #<equal hash-table with 0 entries> Warning: /net/projects/shapiro/clpython/test.fasl not in #<equal hash-table with 0 entries> ; Fast loading /net/projects/shapiro/clpython/test.fasl [...] First question: Why the Warning messages? How can I get rid of them?
Those were debug messages accidentally left in. They have been removed now. Sorry about that.
Notice that I can make use of the values returned by the Python function:
cl-user(4): (setf x (clpython:run "import test; test.test()")) Warning: *import-recompiled-files* = #<equal hash-table with 0 entries> Warning: /net/projects/shapiro/clpython/test.fasl not in #<equal hash-table with 0 entries> ; Fast loading /net/projects/shapiro/clpython/test.fasl The Python test file has been run. Warning: *import-recompiled-files* = #<equal hash-table with 0 entries> Warning: /net/projects/shapiro/clpython/test.fasl not in #<equal hash-table with 0 entries> I am a Python function. "I am done."
cl-user(5): x "I am done."
Yes, the last value of the Python expression is returned.
What I'd really like to do now is to call test.test() as much as possible as though it were a Common Lisp function. One possible way is:
cl-user(6): (clpython:run "test.test()") Error: NameError: Variable `test' is unbound. [condition type: NameError]
Restart actions (select using :continue): 0: Enter a Lisp value to use for `test'. 1: Return to Top Level (an "abort" restart). 2: Abort entirely from this (lisp) process.
But, the name of the function does not seem to survive from one call of clpython:run to another.
Final question: How can I do this?
There is not an elegent way for that yet (I'm working on it), but the following works:
cl-user(6): :pa clpython clpython(7): (setf *habitat* (make-habitat)) ;; required for py-import #<habitat @ #x10fd5472> clpython(8): (setq m (py-import '(foo))) #<module `foo' Src: /Users/willem/dev/lisp/tmp/git-clpython/foo.py Binary: /Users/willem/.fasl/allegro-8.1m-macosx-x86/Users/willem/dev/lisp/tmp/git-clpython/foo.fasl @ #x10a5a5a2> clpython(9): (attr m 'f) ;; attribute lookup #<python-function f @ #x10a5a872> clpython(10): (funcall *) 24 None
Where foo.y is: def f(): print 24
- Willem