aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/org/ob-python.el
diff options
context:
space:
mode:
authorBastien Guerry2020-12-13 13:44:15 +0100
committerBastien Guerry2020-12-13 13:44:15 +0100
commitf22856a5c54d99867cd24c08a14bbda23d5c6229 (patch)
treeb6bd688963531eccb8b9d18195df0edfc34ba59d /lisp/org/ob-python.el
parent6aa9fe3e1b4052b2acde86404a90e35893ebfa00 (diff)
downloademacs-f22856a5c54d99867cd24c08a14bbda23d5c6229.tar.gz
emacs-f22856a5c54d99867cd24c08a14bbda23d5c6229.zip
Update to Org 9.4.1
Diffstat (limited to 'lisp/org/ob-python.el')
-rw-r--r--lisp/org/ob-python.el219
1 files changed, 119 insertions, 100 deletions
diff --git a/lisp/org/ob-python.el b/lisp/org/ob-python.el
index 823f6e63d57..ffb8ee855ef 100644
--- a/lisp/org/ob-python.el
+++ b/lisp/org/ob-python.el
@@ -4,6 +4,7 @@
4 4
5;; Authors: Eric Schulte 5;; Authors: Eric Schulte
6;; Dan Davison 6;; Dan Davison
7;; Maintainer: Jack Kamm <jackkamm@gmail.com>
7;; Keywords: literate programming, reproducible research 8;; Keywords: literate programming, reproducible research
8;; Homepage: https://orgmode.org 9;; Homepage: https://orgmode.org
9 10
@@ -29,10 +30,11 @@
29;;; Code: 30;;; Code:
30(require 'ob) 31(require 'ob)
31(require 'org-macs) 32(require 'org-macs)
33(require 'python)
32 34
33(declare-function py-shell "ext:python-mode" (&optional argprompt)) 35(declare-function py-shell "ext:python-mode" (&rest args))
34(declare-function py-toggle-shells "ext:python-mode" (arg)) 36(declare-function py-toggle-shells "ext:python-mode" (arg))
35(declare-function run-python "ext:python" (&optional cmd dedicated show)) 37(declare-function py-shell-send-string "ext:python-mode" (strg &optional process))
36 38
37(defvar org-babel-tangle-lang-exts) 39(defvar org-babel-tangle-lang-exts)
38(add-to-list 'org-babel-tangle-lang-exts '("python" . "py")) 40(add-to-list 'org-babel-tangle-lang-exts '("python" . "py"))
@@ -104,7 +106,8 @@ VARS contains resolved variable references."
104 (org-babel-comint-in-buffer session 106 (org-babel-comint-in-buffer session
105 (mapc (lambda (var) 107 (mapc (lambda (var)
106 (end-of-line 1) (insert var) (comint-send-input) 108 (end-of-line 1) (insert var) (comint-send-input)
107 (org-babel-comint-wait-for-output session)) var-lines)) 109 (org-babel-comint-wait-for-output session))
110 var-lines))
108 session)) 111 session))
109 112
110(defun org-babel-load-session:python (session body params) 113(defun org-babel-load-session:python (session body params)
@@ -177,42 +180,40 @@ Emacs-lisp table, otherwise return the results as a string."
177 "Initiate a python session. 180 "Initiate a python session.
178If there is not a current inferior-process-buffer in SESSION 181If there is not a current inferior-process-buffer in SESSION
179then create. Return the initialized session." 182then create. Return the initialized session."
180 (require org-babel-python-mode)
181 (save-window-excursion 183 (save-window-excursion
182 (let* ((session (if session (intern session) :default)) 184 (let* ((session (if session (intern session) :default))
183 (python-buffer (org-babel-python-session-buffer session)) 185 (py-buffer (org-babel-python-session-buffer session))
184 (cmd (if (member system-type '(cygwin windows-nt ms-dos)) 186 (cmd (if (member system-type '(cygwin windows-nt ms-dos))
185 (concat org-babel-python-command " -i") 187 (concat org-babel-python-command " -i")
186 org-babel-python-command))) 188 org-babel-python-command)))
187 (cond 189 (cond
188 ((and (eq 'python org-babel-python-mode) 190 ((eq 'python org-babel-python-mode) ; python.el
189 (fboundp 'run-python)) ; python.el 191 (unless py-buffer
190 (if (not (version< "24.1" emacs-version)) 192 (setq py-buffer (org-babel-python-with-earmuffs session)))
191 (run-python cmd) 193 (let ((python-shell-buffer-name
192 (unless python-buffer 194 (org-babel-python-without-earmuffs py-buffer)))
193 (setq python-buffer (org-babel-python-with-earmuffs session))) 195 (run-python cmd)
194 (let ((python-shell-buffer-name 196 (sleep-for 0 10)))
195 (org-babel-python-without-earmuffs python-buffer)))
196 (run-python cmd))))
197 ((and (eq 'python-mode org-babel-python-mode) 197 ((and (eq 'python-mode org-babel-python-mode)
198 (fboundp 'py-shell)) ; python-mode.el 198 (fboundp 'py-shell)) ; python-mode.el
199 (require 'python-mode)
199 ;; Make sure that py-which-bufname is initialized, as otherwise 200 ;; Make sure that py-which-bufname is initialized, as otherwise
200 ;; it will be overwritten the first time a Python buffer is 201 ;; it will be overwritten the first time a Python buffer is
201 ;; created. 202 ;; created.
202 (py-toggle-shells py-default-interpreter) 203 (py-toggle-shells py-default-interpreter)
203 ;; `py-shell' creates a buffer whose name is the value of 204 ;; `py-shell' creates a buffer whose name is the value of
204 ;; `py-which-bufname' with '*'s at the beginning and end 205 ;; `py-which-bufname' with '*'s at the beginning and end
205 (let* ((bufname (if (and python-buffer (buffer-live-p python-buffer)) 206 (let* ((bufname (if (and py-buffer (buffer-live-p py-buffer))
206 (replace-regexp-in-string ;; zap surrounding * 207 (replace-regexp-in-string ;; zap surrounding *
207 "^\\*\\([^*]+\\)\\*$" "\\1" python-buffer) 208 "^\\*\\([^*]+\\)\\*$" "\\1" py-buffer)
208 (concat "Python-" (symbol-name session)))) 209 (concat "Python-" (symbol-name session))))
209 (py-which-bufname bufname)) 210 (py-which-bufname bufname))
210 (py-shell) 211 (setq py-buffer (org-babel-python-with-earmuffs bufname))
211 (setq python-buffer (org-babel-python-with-earmuffs bufname)))) 212 (py-shell nil nil t org-babel-python-command py-buffer nil nil t nil)))
212 (t 213 (t
213 (error "No function available for running an inferior Python"))) 214 (error "No function available for running an inferior Python")))
214 (setq org-babel-python-buffers 215 (setq org-babel-python-buffers
215 (cons (cons session python-buffer) 216 (cons (cons session py-buffer)
216 (assq-delete-all session org-babel-python-buffers))) 217 (assq-delete-all session org-babel-python-buffers)))
217 session))) 218 session)))
218 219
@@ -222,8 +223,9 @@ then create. Return the initialized session."
222 (org-babel-python-session-buffer 223 (org-babel-python-session-buffer
223 (org-babel-python-initiate-session-by-key session)))) 224 (org-babel-python-initiate-session-by-key session))))
224 225
225(defvar org-babel-python-eoe-indicator "'org_babel_python_eoe'" 226(defvar org-babel-python-eoe-indicator "org_babel_python_eoe"
226 "A string to indicate that evaluation has completed.") 227 "A string to indicate that evaluation has completed.")
228
227(defconst org-babel-python-wrapper-method 229(defconst org-babel-python-wrapper-method
228 " 230 "
229def main(): 231def main():
@@ -238,14 +240,39 @@ def main():
238 240
239open('%s', 'w').write( pprint.pformat(main()) )") 241open('%s', 'w').write( pprint.pformat(main()) )")
240 242
241(defconst org-babel-python--exec-tmpfile 243(defconst org-babel-python--exec-tmpfile "\
242 (concat 244with open('%s') as __org_babel_python_tmpfile:
243 "__org_babel_python_fname = '%s'; " 245 exec(compile(__org_babel_python_tmpfile.read(), __org_babel_python_tmpfile.name, 'exec'))"
244 "__org_babel_python_fh = open(__org_babel_python_fname); " 246 "Template for Python session command with output results.
245 "exec(compile(" 247
246 "__org_babel_python_fh.read(), __org_babel_python_fname, 'exec'" 248Has a single %s escape, the tempfile containing the source code
247 ")); " 249to evaluate.")
248 "__org_babel_python_fh.close()")) 250
251(defun org-babel-python-format-session-value
252 (src-file result-file result-params)
253 "Return Python code to evaluate SRC-FILE and write result to RESULT-FILE."
254 (format "\
255import ast
256with open('%s') as __org_babel_python_tmpfile:
257 __org_babel_python_ast = ast.parse(__org_babel_python_tmpfile.read())
258__org_babel_python_final = __org_babel_python_ast.body[-1]
259if isinstance(__org_babel_python_final, ast.Expr):
260 __org_babel_python_ast.body = __org_babel_python_ast.body[:-1]
261 exec(compile(__org_babel_python_ast, '<string>', 'exec'))
262 __org_babel_python_final = eval(compile(ast.Expression(
263 __org_babel_python_final.value), '<string>', 'eval'))
264 with open('%s', 'w') as __org_babel_python_tmpfile:
265 if %s:
266 import pprint
267 __org_babel_python_tmpfile.write(pprint.pformat(__org_babel_python_final))
268 else:
269 __org_babel_python_tmpfile.write(str(__org_babel_python_final))
270else:
271 exec(compile(__org_babel_python_ast, '<string>', 'exec'))
272 __org_babel_python_final = None"
273 (org-babel-process-file-name src-file 'noquote)
274 (org-babel-process-file-name result-file 'noquote)
275 (if (member "pp" result-params) "True" "False")))
249 276
250(defun org-babel-python-evaluate 277(defun org-babel-python-evaluate
251 (session body &optional result-type result-params preamble) 278 (session body &optional result-type result-params preamble)
@@ -256,6 +283,19 @@ open('%s', 'w').write( pprint.pformat(main()) )")
256 (org-babel-python-evaluate-external-process 283 (org-babel-python-evaluate-external-process
257 body result-type result-params preamble))) 284 body result-type result-params preamble)))
258 285
286(defun org-babel-python--shift-right (body &optional count)
287 (with-temp-buffer
288 (python-mode)
289 (insert body)
290 (goto-char (point-min))
291 (while (not (eobp))
292 (unless (python-syntax-context 'string)
293 (python-indent-shift-right (line-beginning-position)
294 (line-end-position)
295 count))
296 (forward-line 1))
297 (buffer-string)))
298
259(defun org-babel-python-evaluate-external-process 299(defun org-babel-python-evaluate-external-process
260 (body &optional result-type result-params preamble) 300 (body &optional result-type result-params preamble)
261 "Evaluate BODY in external python process. 301 "Evaluate BODY in external python process.
@@ -276,89 +316,70 @@ last statement in BODY, as elisp."
276 (if (member "pp" result-params) 316 (if (member "pp" result-params)
277 org-babel-python-pp-wrapper-method 317 org-babel-python-pp-wrapper-method
278 org-babel-python-wrapper-method) 318 org-babel-python-wrapper-method)
279 (mapconcat 319 (org-babel-python--shift-right body)
280 (lambda (line) (format "\t%s" line))
281 (split-string (org-remove-indentation (org-trim body))
282 "[\r\n]")
283 "\n")
284 (org-babel-process-file-name tmp-file 'noquote)))) 320 (org-babel-process-file-name tmp-file 'noquote))))
285 (org-babel-eval-read-file tmp-file)))))) 321 (org-babel-eval-read-file tmp-file))))))
286 (org-babel-result-cond result-params 322 (org-babel-result-cond result-params
287 raw 323 raw
288 (org-babel-python-table-or-string (org-trim raw))))) 324 (org-babel-python-table-or-string (org-trim raw)))))
289 325
326(defun org-babel-python--send-string (session body)
327 "Pass BODY to the Python process in SESSION.
328Return output."
329 (with-current-buffer session
330 (let* ((string-buffer "")
331 (comint-output-filter-functions
332 (cons (lambda (text) (setq string-buffer
333 (concat string-buffer text)))
334 comint-output-filter-functions))
335 (body (format "\
336try:
337%s
338except:
339 raise
340finally:
341 print('%s')"
342 (org-babel-python--shift-right body 4)
343 org-babel-python-eoe-indicator)))
344 (if (not (eq 'python-mode org-babel-python-mode))
345 (let ((python-shell-buffer-name
346 (org-babel-python-without-earmuffs session)))
347 (python-shell-send-string body))
348 (require 'python-mode)
349 (py-shell-send-string body (get-buffer-process session)))
350 ;; same as `python-shell-comint-end-of-output-p' in emacs-25.1+
351 (while (not (string-match
352 org-babel-python-eoe-indicator
353 string-buffer))
354 (accept-process-output (get-buffer-process (current-buffer))))
355 (org-babel-chomp (substring string-buffer 0 (match-beginning 0))))))
356
290(defun org-babel-python-evaluate-session 357(defun org-babel-python-evaluate-session
291 (session body &optional result-type result-params) 358 (session body &optional result-type result-params)
292 "Pass BODY to the Python process in SESSION. 359 "Pass BODY to the Python process in SESSION.
293If RESULT-TYPE equals `output' then return standard output as a 360If RESULT-TYPE equals `output' then return standard output as a
294string. If RESULT-TYPE equals `value' then return the value of the 361string. If RESULT-TYPE equals `value' then return the value of the
295last statement in BODY, as elisp." 362last statement in BODY, as elisp."
296 (let* ((send-wait (lambda () (comint-send-input nil t) (sleep-for 0 5))) 363 (let* ((tmp-src-file (org-babel-temp-file "python-"))
297 (dump-last-value
298 (lambda
299 (tmp-file pp)
300 (mapc
301 (lambda (statement) (insert statement) (funcall send-wait))
302 (if pp
303 (list
304 "import pprint"
305 (format "open('%s', 'w').write(pprint.pformat(_))"
306 (org-babel-process-file-name tmp-file 'noquote)))
307 (list (format "open('%s', 'w').write(str(_))"
308 (org-babel-process-file-name tmp-file
309 'noquote)))))))
310 (last-indent 0)
311 (input-body (lambda (body)
312 (dolist (line (split-string body "[\r\n]"))
313 ;; Insert a blank line to end an indent
314 ;; block.
315 (let ((curr-indent (string-match "\\S-" line)))
316 (if curr-indent
317 (progn
318 (when (< curr-indent last-indent)
319 (insert "")
320 (funcall send-wait))
321 (setq last-indent curr-indent))
322 (setq last-indent 0)))
323 (insert line)
324 (funcall send-wait))
325 (funcall send-wait)))
326 (results 364 (results
327 (pcase result-type 365 (progn
328 (`output 366 (with-temp-file tmp-src-file (insert body))
329 (let ((body (if (string-match-p ".\n+." body) ; Multiline 367 (pcase result-type
330 (let ((tmp-src-file (org-babel-temp-file 368 (`output
331 "python-"))) 369 (let ((body (format org-babel-python--exec-tmpfile
332 (with-temp-file tmp-src-file (insert body)) 370 (org-babel-process-file-name
333 (format org-babel-python--exec-tmpfile 371 tmp-src-file 'noquote))))
334 tmp-src-file)) 372 (org-babel-python--send-string session body)))
335 body))) 373 (`value
336 (mapconcat 374 (let* ((tmp-results-file (org-babel-temp-file "python-"))
337 #'org-trim 375 (body (org-babel-python-format-session-value
338 (butlast 376 tmp-src-file tmp-results-file result-params)))
339 (org-babel-comint-with-output 377 (org-babel-python--send-string session body)
340 (session org-babel-python-eoe-indicator t body) 378 (sleep-for 0 10)
341 (funcall input-body body) 379 (org-babel-eval-read-file tmp-results-file)))))))
342 (funcall send-wait) (funcall send-wait) 380 (org-babel-result-cond result-params
343 (insert org-babel-python-eoe-indicator) 381 results
344 (funcall send-wait)) 382 (org-babel-python-table-or-string results))))
345 2) "\n")))
346 (`value
347 (let ((tmp-file (org-babel-temp-file "python-")))
348 (org-babel-comint-with-output
349 (session org-babel-python-eoe-indicator nil body)
350 (let ((comint-process-echoes nil))
351 (funcall input-body body)
352 (funcall dump-last-value tmp-file
353 (member "pp" result-params))
354 (funcall send-wait) (funcall send-wait)
355 (insert org-babel-python-eoe-indicator)
356 (funcall send-wait)))
357 (org-babel-eval-read-file tmp-file))))))
358 (unless (string= (substring org-babel-python-eoe-indicator 1 -1) results)
359 (org-babel-result-cond result-params
360 results
361 (org-babel-python-table-or-string results)))))
362 383
363(defun org-babel-python-read-string (string) 384(defun org-babel-python-read-string (string)
364 "Strip \\='s from around Python string." 385 "Strip \\='s from around Python string."
@@ -369,6 +390,4 @@ last statement in BODY, as elisp."
369 390
370(provide 'ob-python) 391(provide 'ob-python)
371 392
372
373
374;;; ob-python.el ends here 393;;; ob-python.el ends here