diff options
| author | Augusto Stoffel | 2021-09-03 14:26:51 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-09-03 14:26:51 +0200 |
| commit | e32c7d2a8d1635af5234a8ceabbdbe911abc9a7b (patch) | |
| tree | 01f706c3efd2e4051b53416343a107dec9a7a4d9 /lisp/progmodes/python.el | |
| parent | 34550b44924cac96ece0ae0cd215dea433dd863a (diff) | |
| download | emacs-e32c7d2a8d1635af5234a8ceabbdbe911abc9a7b.tar.gz emacs-e32c7d2a8d1635af5234a8ceabbdbe911abc9a7b.zip | |
Change Python eval to send directly instead of using temporary files
* lisp/progmodes/python.el (python-shell-eval-setup-code): New
const for setting up eval (bug#49822).
(python-shell--encode-string): New function.
(python-shell-send-string): Use it to send commands directly
instead of writing to a temporary file.
(python-shell-send-string-no-output): Adjust sending.
(python-shell-send-file): Ditto.
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 64 |
1 files changed, 50 insertions, 14 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index d5209d8d2f1..306cc3a5428 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -3081,6 +3081,45 @@ there for compatibility with CEDET.") | |||
| 3081 | (delete-trailing-whitespace)) | 3081 | (delete-trailing-whitespace)) |
| 3082 | temp-file-name)) | 3082 | temp-file-name)) |
| 3083 | 3083 | ||
| 3084 | (defconst python-shell-eval-setup-code | ||
| 3085 | "\ | ||
| 3086 | def __PYTHON_EL_eval(source, filename): | ||
| 3087 | import ast, sys | ||
| 3088 | if sys.version_info[0] == 2: | ||
| 3089 | from __builtin__ import compile, eval, globals | ||
| 3090 | else: | ||
| 3091 | from builtins import compile, eval, globals | ||
| 3092 | sys.stdout.write('\\n') | ||
| 3093 | try: | ||
| 3094 | p, e = ast.parse(source, filename), None | ||
| 3095 | except SyntaxError: | ||
| 3096 | t, v, tb = sys.exc_info() | ||
| 3097 | sys.excepthook(t, v, tb.tb_next) | ||
| 3098 | return | ||
| 3099 | if p.body and isinstance(p.body[-1], ast.Expr): | ||
| 3100 | e = p.body.pop() | ||
| 3101 | try: | ||
| 3102 | g = globals() | ||
| 3103 | exec(compile(p, filename, 'exec'), g, g) | ||
| 3104 | if e: | ||
| 3105 | return eval(compile(ast.Expression(e.value), filename, 'eval'), g, g) | ||
| 3106 | except Exception: | ||
| 3107 | t, v, tb = sys.exc_info() | ||
| 3108 | sys.excepthook(t, v, tb.tb_next)" | ||
| 3109 | "Code used to evaluate statements in inferior Python processes.") | ||
| 3110 | |||
| 3111 | (defalias 'python-shell--encode-string | ||
| 3112 | (let ((fun (if (and (fboundp 'json-serialize) | ||
| 3113 | (>= emacs-major-version 28)) | ||
| 3114 | 'json-serialize | ||
| 3115 | (require 'json) | ||
| 3116 | 'json-encode-string))) | ||
| 3117 | (lambda (text) | ||
| 3118 | (if (stringp text) | ||
| 3119 | (funcall fun text) | ||
| 3120 | (signal 'wrong-type-argument (list 'stringp text))))) | ||
| 3121 | "Encode TEXT as a valid Python string.") | ||
| 3122 | |||
| 3084 | (defun python-shell-send-string (string &optional process msg) | 3123 | (defun python-shell-send-string (string &optional process msg) |
| 3085 | "Send STRING to inferior Python PROCESS. | 3124 | "Send STRING to inferior Python PROCESS. |
| 3086 | When optional argument MSG is non-nil, forces display of a | 3125 | When optional argument MSG is non-nil, forces display of a |
| @@ -3088,16 +3127,12 @@ user-friendly message if there's no process running; defaults to | |||
| 3088 | t when called interactively." | 3127 | t when called interactively." |
| 3089 | (interactive | 3128 | (interactive |
| 3090 | (list (read-string "Python command: ") nil t)) | 3129 | (list (read-string "Python command: ") nil t)) |
| 3091 | (let ((process (or process (python-shell-get-process-or-error msg)))) | 3130 | (comint-send-string |
| 3092 | (if (string-match ".\n+." string) ;Multiline. | 3131 | (or process (python-shell-get-process-or-error msg)) |
| 3093 | (let* ((temp-file-name (with-current-buffer (process-buffer process) | 3132 | (format "exec(%s);__PYTHON_EL_eval(%s, %s)\n" |
| 3094 | (python-shell--save-temp-file string))) | 3133 | (python-shell--encode-string python-shell-eval-setup-code) |
| 3095 | (file-name (or (buffer-file-name) temp-file-name))) | 3134 | (python-shell--encode-string string) |
| 3096 | (python-shell-send-file file-name process temp-file-name t)) | 3135 | (python-shell--encode-string (or (buffer-file-name) "<string>"))))) |
| 3097 | (comint-send-string process string) | ||
| 3098 | (when (or (not (string-match "\n\\'" string)) | ||
| 3099 | (string-match "\n[ \t].*\n?\\'" string)) | ||
| 3100 | (comint-send-string process "\n"))))) | ||
| 3101 | 3136 | ||
| 3102 | (defvar python-shell-output-filter-in-progress nil) | 3137 | (defvar python-shell-output-filter-in-progress nil) |
| 3103 | (defvar python-shell-output-filter-buffer nil) | 3138 | (defvar python-shell-output-filter-buffer nil) |
| @@ -3139,7 +3174,8 @@ Return the output." | |||
| 3139 | (inhibit-quit t)) | 3174 | (inhibit-quit t)) |
| 3140 | (or | 3175 | (or |
| 3141 | (with-local-quit | 3176 | (with-local-quit |
| 3142 | (python-shell-send-string string process) | 3177 | (comint-send-string |
| 3178 | process (format "exec(%s)\n" (python-shell--encode-string string))) | ||
| 3143 | (while python-shell-output-filter-in-progress | 3179 | (while python-shell-output-filter-in-progress |
| 3144 | ;; `python-shell-output-filter' takes care of setting | 3180 | ;; `python-shell-output-filter' takes care of setting |
| 3145 | ;; `python-shell-output-filter-in-progress' to NIL after it | 3181 | ;; `python-shell-output-filter-in-progress' to NIL after it |
| @@ -3362,7 +3398,8 @@ t when called interactively." | |||
| 3362 | (temp-file-name (when temp-file-name | 3398 | (temp-file-name (when temp-file-name |
| 3363 | (file-local-name (expand-file-name | 3399 | (file-local-name (expand-file-name |
| 3364 | temp-file-name))))) | 3400 | temp-file-name))))) |
| 3365 | (python-shell-send-string | 3401 | (comint-send-string |
| 3402 | process | ||
| 3366 | (format | 3403 | (format |
| 3367 | (concat | 3404 | (concat |
| 3368 | "import codecs, os;" | 3405 | "import codecs, os;" |
| @@ -3372,8 +3409,7 @@ t when called interactively." | |||
| 3372 | (when (and delete temp-file-name) | 3409 | (when (and delete temp-file-name) |
| 3373 | (format "os.remove('''%s''');" temp-file-name)) | 3410 | (format "os.remove('''%s''');" temp-file-name)) |
| 3374 | "exec(compile(__code, '''%s''', 'exec'));") | 3411 | "exec(compile(__code, '''%s''', 'exec'));") |
| 3375 | (or temp-file-name file-name) encoding encoding file-name) | 3412 | (or temp-file-name file-name) encoding encoding file-name)))) |
| 3376 | process))) | ||
| 3377 | 3413 | ||
| 3378 | (defun python-shell-switch-to-shell (&optional msg) | 3414 | (defun python-shell-switch-to-shell (&optional msg) |
| 3379 | "Switch to inferior Python process buffer. | 3415 | "Switch to inferior Python process buffer. |