]> code.delx.au - gnu-emacs/blobdiff - lisp/org/ob-python.el
merge trunk
[gnu-emacs] / lisp / org / ob-python.el
index b53513a212c19613b9bcd523ae0bcae18ffec4f2..79cc53ea0fa8dc1c7b7f0061fd7092d2d9e0b9a3 100644 (file)
@@ -1,11 +1,11 @@
 ;;; ob-python.el --- org-babel functions for python evaluation
 
-;; Copyright (C) 2009-2011  Free Software Foundation
+;; Copyright (C) 2009-2013 Free Software Foundation, Inc.
 
-;; Author: Eric Schulte, Dan Davison
+;; Authors: Eric Schulte
+;;      Dan Davison
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: http://orgmode.org
-;; Version: 7.4
 
 ;; This file is part of GNU Emacs.
 
 
 (declare-function org-remove-indentation "org" )
 (declare-function py-shell "ext:python-mode" (&optional argprompt))
+(declare-function py-toggle-shells "ext:python-mode" (arg))
 (declare-function run-python "ext:python" (&optional cmd noshow new))
 
+(defvar org-babel-tangle-lang-exts)
 (add-to-list 'org-babel-tangle-lang-exts '("python" . "py"))
 
 (defvar org-babel-default-header-args:python '())
 
 (defvar org-babel-python-command "python"
-  "Name of command for executing python code.")
+  "Name of the command for executing Python code.")
 
 (defvar org-babel-python-mode (if (featurep 'xemacs) 'python-mode 'python)
-  "Preferred python mode for use in running python interactively.")
+  "Preferred python mode for use in running python interactively.
+This will typically be either 'python or 'python-mode.")
 
 (defvar org-src-preserve-indentation)
 
@@ -61,17 +64,16 @@ This function is called by `org-babel-execute-src-block'."
         (preamble (cdr (assoc :preamble params)))
          (full-body
          (org-babel-expand-body:generic
-          (concat body (if return-val (format "return %s" return-val) ""))
+          (concat body (if return-val (format "\nreturn %s" return-val) ""))
           params (org-babel-variable-assignments:python params)))
          (result (org-babel-python-evaluate
                  session full-body result-type result-params preamble)))
-    (or (cdr (assoc :file params))
-        (org-babel-reassemble-table
-         result
-         (org-babel-pick-name (cdr (assoc :colname-names params))
-                             (cdr (assoc :colnames params)))
-         (org-babel-pick-name (cdr (assoc :rowname-names params))
-                             (cdr (assoc :rownames params)))))))
+    (org-babel-reassemble-table
+     result
+     (org-babel-pick-name (cdr (assoc :colname-names params))
+                         (cdr (assoc :colnames params)))
+     (org-babel-pick-name (cdr (assoc :rowname-names params))
+                         (cdr (assoc :rownames params))))))
 
 (defun org-babel-prep-session:python (session params)
   "Prepare SESSION according to the header arguments in PARAMS.
@@ -97,7 +99,7 @@ VARS contains resolved variable references"
 ;; helper functions
 
 (defun org-babel-variable-assignments:python (params)
-  "Return list of python statements assigning the block's variables"
+  "Return a list of Python statements assigning the block's variables."
   (mapcar
    (lambda (pair)
      (format "%s=%s"
@@ -129,6 +131,7 @@ Emacs-lisp table, otherwise return the results as a string."
   "Return the buffer associated with SESSION."
   (cdr (assoc session org-babel-python-buffers)))
 
+(defvar py-default-interpreter)
 (defun org-babel-python-initiate-session-by-key (&optional session)
   "Initiate a python session.
 If there is not a current inferior-process-buffer in SESSION
@@ -140,12 +143,18 @@ then create.  Return the initialized session."
       (cond
        ((and (eq 'python org-babel-python-mode)
             (fboundp 'run-python)) ; python.el
-       (run-python))
+       (if (version< "24.1" emacs-version)
+           (run-python org-babel-python-command)
+         (run-python)))
        ((and (eq 'python-mode org-babel-python-mode)
             (fboundp 'py-shell)) ; python-mode.el
+       ;; Make sure that py-which-bufname is initialized, as otherwise
+       ;; it will be overwritten the first time a Python buffer is
+       ;; created.
+       (py-toggle-shells py-default-interpreter)
        ;; `py-shell' creates a buffer whose name is the value of
        ;; `py-which-bufname' with '*'s at the beginning and end
-       (let* ((bufname (if python-buffer
+       (let* ((bufname (if (and python-buffer (buffer-live-p python-buffer))
                            (replace-regexp-in-string ;; zap surrounding *
                             "^\\*\\([^*]+\\)\\*$" "\\1" python-buffer)
                          (concat "Python-" (symbol-name session))))
@@ -153,7 +162,7 @@ then create.  Return the initialized session."
          (py-shell)
          (setq python-buffer (concat "*" bufname "*"))))
        (t
-       (error "No function available for running an inferior python.")))
+       (error "No function available for running an inferior Python")))
       (setq org-babel-python-buffers
            (cons (cons session python-buffer)
                  (assq-delete-all session org-babel-python-buffers)))
@@ -183,7 +192,7 @@ open('%s', 'w').write( pprint.pformat(main()) )")
 
 (defun org-babel-python-evaluate
   (session body &optional result-type result-params preamble)
-  "Evaluate BODY as python code."
+  "Evaluate BODY as Python code."
   (if session
       (org-babel-python-evaluate-session
        session body result-type result-params)
@@ -194,83 +203,94 @@ open('%s', 'w').write( pprint.pformat(main()) )")
   (body &optional result-type result-params preamble)
   "Evaluate BODY in external python process.
 If RESULT-TYPE equals 'output then return standard output as a
-string. If RESULT-TYPE equals 'value then return the value of the
+string.  If RESULT-TYPE equals 'value then return the value of the
 last statement in BODY, as elisp."
-  (case result-type
-    (output (org-babel-eval org-babel-python-command
-                           (concat (if preamble (concat preamble "\n") "") body)))
-    (value (let ((tmp-file (org-babel-temp-file "python-")))
-            (org-babel-eval org-babel-python-command
-                            (concat
-                             (if preamble (concat preamble "\n") "")
-                             (format
-                              (if (member "pp" result-params)
-                                  org-babel-python-pp-wrapper-method
-                                org-babel-python-wrapper-method)
-                              (mapconcat
-                               (lambda (line) (format "\t%s" line))
-                               (split-string
-                                (org-remove-indentation
-                                 (org-babel-trim body))
-                                "[\r\n]") "\n")
-                              (org-babel-process-file-name tmp-file 'noquote))))
-            ((lambda (raw)
-               (if (or (member "code" result-params)
-                       (member "pp" result-params))
-                   raw
-                 (org-babel-python-table-or-string raw)))
+  ((lambda (raw)
+     (if (or (member "code" result-params)
+            (member "pp" result-params)
+            (and (member "output" result-params)
+                 (not (member "table" result-params))))
+        raw
+       (org-babel-python-table-or-string (org-babel-trim raw))))
+   (case result-type
+     (output (org-babel-eval org-babel-python-command
+                            (concat (if preamble (concat preamble "\n") "")
+                                    body)))
+     (value (let ((tmp-file (org-babel-temp-file "python-")))
+             (org-babel-eval
+              org-babel-python-command
+              (concat
+               (if preamble (concat preamble "\n") "")
+               (format
+                (if (member "pp" result-params)
+                    org-babel-python-pp-wrapper-method
+                  org-babel-python-wrapper-method)
+                (mapconcat
+                 (lambda (line) (format "\t%s" line))
+                 (split-string
+                  (org-remove-indentation
+                   (org-babel-trim body))
+                  "[\r\n]") "\n")
+                (org-babel-process-file-name tmp-file 'noquote))))
              (org-babel-eval-read-file tmp-file))))))
 
 (defun org-babel-python-evaluate-session
   (session body &optional result-type result-params)
   "Pass BODY to the Python process in SESSION.
 If RESULT-TYPE equals 'output then return standard output as a
-string. If RESULT-TYPE equals 'value then return the value of the
+string.  If RESULT-TYPE equals 'value then return the value of the
 last statement in BODY, as elisp."
-  (flet ((dump-last-value
-         (tmp-file pp)
-         (mapc
-          (lambda (statement) (insert statement) (comint-send-input))
-          (if pp
-              (list
-               "import pprint"
-               (format "open('%s', 'w').write(pprint.pformat(_))"
-                       (org-babel-process-file-name tmp-file 'noquote)))
-            (list (format "open('%s', 'w').write(str(_))"
-                          (org-babel-process-file-name tmp-file 'noquote))))))
-        (input-body (body)
-                    (mapc (lambda (statement) (insert statement) (comint-send-input))
-                          (split-string (org-babel-trim body) "[\r\n]+"))
-                    (comint-send-input) (comint-send-input)))
-    (case result-type
-      (output
-       (mapconcat
-       #'org-babel-trim
-       (butlast
-        (org-babel-comint-with-output
-            (session org-babel-python-eoe-indicator t body)
-          (let ((comint-process-echoes nil))
-            (input-body body)
-            (insert org-babel-python-eoe-indicator)
-            (comint-send-input))) 2) "\n"))
-      (value
-       ((lambda (results)
-         (if (or (member "code" result-params) (member "pp" result-params))
-             results
-           (org-babel-python-table-or-string results)))
-       (let ((tmp-file (org-babel-temp-file "python-")))
+  (let* ((send-wait (lambda () (comint-send-input nil t) (sleep-for 0 5)))
+        (dump-last-value
+         (lambda
+           (tmp-file pp)
+           (mapc
+            (lambda (statement) (insert statement) (funcall send-wait))
+            (if pp
+                (list
+                 "import pprint"
+                 (format "open('%s', 'w').write(pprint.pformat(_))"
+                         (org-babel-process-file-name tmp-file 'noquote)))
+              (list (format "open('%s', 'w').write(str(_))"
+                            (org-babel-process-file-name tmp-file 'noquote)))))))
+        (input-body (lambda (body)
+                      (mapc (lambda (line) (insert line) (funcall send-wait))
+                            (split-string body "[\r\n]"))
+                      (funcall send-wait))))
+    ((lambda (results)
+       (unless (string= (substring org-babel-python-eoe-indicator 1 -1) results)
+        (if (or (member "code" result-params)
+                (member "pp" result-params)
+                (and (member "output" result-params)
+                     (not (member "table" result-params))))
+            results
+          (org-babel-python-table-or-string results))))
+     (case result-type
+       (output
+       (mapconcat
+        #'org-babel-trim
+        (butlast
          (org-babel-comint-with-output
              (session org-babel-python-eoe-indicator t body)
+           (funcall input-body body)
+           (funcall send-wait) (funcall send-wait)
+           (insert org-babel-python-eoe-indicator)
+           (funcall send-wait))
+         2) "\n"))
+       (value
+       (let ((tmp-file (org-babel-temp-file "python-")))
+         (org-babel-comint-with-output
+             (session org-babel-python-eoe-indicator nil body)
            (let ((comint-process-echoes nil))
-             (input-body body)
-             (dump-last-value tmp-file (member "pp" result-params))
-             (comint-send-input) (comint-send-input)
+             (funcall input-body body)
+             (funcall dump-last-value tmp-file (member "pp" result-params))
+             (funcall send-wait) (funcall send-wait)
              (insert org-babel-python-eoe-indicator)
-             (comint-send-input)))
+             (funcall send-wait)))
          (org-babel-eval-read-file tmp-file)))))))
 
 (defun org-babel-python-read-string (string)
-  "Strip 's from around python string"
+  "Strip 's from around Python string."
   (if (string-match "^'\\([^\000]+\\)'$" string)
       (match-string 1 string)
     string))
@@ -278,4 +298,5 @@ last statement in BODY, as elisp."
 (provide 'ob-python)
 
 
+
 ;;; ob-python.el ends here