aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
authorAugusto Stoffel2021-09-09 15:48:37 +0200
committerLars Ingebrigtsen2021-09-09 15:48:37 +0200
commite27385ec372b36822958ebed6792ca806b1a0c3d (patch)
tree3e9cbf40e4bbc1df424f5d7dabe95e58db8f80e8 /lisp/progmodes/python.el
parent2be75990a7ae611e8596a91b5e124dc421ec93b4 (diff)
downloademacs-e27385ec372b36822958ebed6792ca806b1a0c3d.tar.gz
emacs-e27385ec372b36822958ebed6792ca806b1a0c3d.zip
Better treatment of line length limits for the Python inferior
* lisp/comint.el (comint-max-line-length): New constant reflecting a safe maximum line size that can be sent to an inferior process. * lisp/progmodes/python.el (python-shell-comint-watch-for-first-prompt-output-filter): Send setup code to the inferior process only once and at this stage. (python-shell-eval-setup-code, python-shell-eval-file-setup-code): Move, unchanged, to an earlier point to avoid byte-compiler warnings. (python-shell-send-string-no-output): Revert changes of e32c7d2a8d (python-shell-send-string): Use 'comint-max-line-length' to decide when to resort to temp files. (python-shell-send-string, python-shell-send-file): Don't send setup code each time (bug#49822).
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el98
1 files changed, 51 insertions, 47 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index db7008df244..8f7bb7a8b60 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2811,6 +2811,44 @@ eventually provide a shell."
2811 :type 'hook 2811 :type 'hook
2812 :group 'python) 2812 :group 'python)
2813 2813
2814(defconst python-shell-eval-setup-code
2815 "\
2816def __PYTHON_EL_eval(source, filename):
2817 import ast, sys
2818 if sys.version_info[0] == 2:
2819 from __builtin__ import compile, eval, globals
2820 else:
2821 from builtins import compile, eval, globals
2822 sys.stdout.write('\\n')
2823 try:
2824 p, e = ast.parse(source, filename), None
2825 except SyntaxError:
2826 t, v, tb = sys.exc_info()
2827 sys.excepthook(t, v, tb.tb_next)
2828 return
2829 if p.body and isinstance(p.body[-1], ast.Expr):
2830 e = p.body.pop()
2831 try:
2832 g = globals()
2833 exec(compile(p, filename, 'exec'), g, g)
2834 if e:
2835 return eval(compile(ast.Expression(e.value), filename, 'eval'), g, g)
2836 except Exception:
2837 t, v, tb = sys.exc_info()
2838 sys.excepthook(t, v, tb.tb_next)"
2839 "Code used to evaluate statements in inferior Python processes.")
2840
2841(defconst python-shell-eval-file-setup-code
2842 "\
2843def __PYTHON_EL_eval_file(filename, tempname, encoding, delete):
2844 import codecs, os
2845 with codecs.open(tempname or filename, encoding=encoding) as file:
2846 source = file.read().encode(encoding)
2847 if delete and tempname:
2848 os.remove(tempname)
2849 return __PYTHON_EL_eval(source, filename)"
2850 "Code used to evaluate files in inferior Python processes.")
2851
2814(defun python-shell-comint-watch-for-first-prompt-output-filter (output) 2852(defun python-shell-comint-watch-for-first-prompt-output-filter (output)
2815 "Run `python-shell-first-prompt-hook' when first prompt is found in OUTPUT." 2853 "Run `python-shell-first-prompt-hook' when first prompt is found in OUTPUT."
2816 (when (not python-shell--first-prompt-received) 2854 (when (not python-shell--first-prompt-received)
@@ -2826,6 +2864,15 @@ eventually provide a shell."
2826 (setq python-shell--first-prompt-received-output-buffer nil) 2864 (setq python-shell--first-prompt-received-output-buffer nil)
2827 (setq-local python-shell--first-prompt-received t) 2865 (setq-local python-shell--first-prompt-received t)
2828 (setq python-shell--first-prompt-received-output-buffer nil) 2866 (setq python-shell--first-prompt-received-output-buffer nil)
2867 (cl-letf (((symbol-function 'python-shell-send-string)
2868 (lambda (string process)
2869 (comint-send-string
2870 process
2871 (format "exec(%s)\n" (python-shell--encode-string string))))))
2872 ;; Bootstrap: the normal definition of `python-shell-send-string'
2873 ;; depends on the Python code sent here.
2874 (python-shell-send-string-no-output python-shell-eval-setup-code)
2875 (python-shell-send-string-no-output python-shell-eval-file-setup-code))
2829 (with-current-buffer (current-buffer) 2876 (with-current-buffer (current-buffer)
2830 (let ((inhibit-quit nil)) 2877 (let ((inhibit-quit nil))
2831 (run-hooks 'python-shell-first-prompt-hook)))))) 2878 (run-hooks 'python-shell-first-prompt-hook))))))
@@ -3081,33 +3128,6 @@ there for compatibility with CEDET.")
3081 (delete-trailing-whitespace)) 3128 (delete-trailing-whitespace))
3082 temp-file-name)) 3129 temp-file-name))
3083 3130
3084(defconst python-shell-eval-setup-code
3085 "\
3086def __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 3131(defalias 'python-shell--encode-string
3112 (let ((fun (if (and (fboundp 'json-serialize) 3132 (let ((fun (if (and (fboundp 'json-serialize)
3113 (>= emacs-major-version 28)) 3133 (>= emacs-major-version 28))
@@ -3128,12 +3148,11 @@ t when called interactively."
3128 (interactive 3148 (interactive
3129 (list (read-string "Python command: ") nil t)) 3149 (list (read-string "Python command: ") nil t))
3130 (let ((process (or process (python-shell-get-process-or-error msg))) 3150 (let ((process (or process (python-shell-get-process-or-error msg)))
3131 (code (format "exec(%s);__PYTHON_EL_eval(%s, %s)\n" 3151 (code (format "__PYTHON_EL_eval(%s, %s)\n"
3132 (python-shell--encode-string python-shell-eval-setup-code)
3133 (python-shell--encode-string string) 3152 (python-shell--encode-string string)
3134 (python-shell--encode-string (or (buffer-file-name) 3153 (python-shell--encode-string (or (buffer-file-name)
3135 "<string>"))))) 3154 "<string>")))))
3136 (if (<= (string-bytes code) 4096) 3155 (if (<= (string-bytes code) comint-max-line-length)
3137 (comint-send-string process code) 3156 (comint-send-string process code)
3138 (let* ((temp-file-name (with-current-buffer (process-buffer process) 3157 (let* ((temp-file-name (with-current-buffer (process-buffer process)
3139 (python-shell--save-temp-file string))) 3158 (python-shell--save-temp-file string)))
@@ -3180,8 +3199,7 @@ Return the output."
3180 (inhibit-quit t)) 3199 (inhibit-quit t))
3181 (or 3200 (or
3182 (with-local-quit 3201 (with-local-quit
3183 (comint-send-string 3202 (python-shell-send-string string process)
3184 process (format "exec(%s)\n" (python-shell--encode-string string)))
3185 (while python-shell-output-filter-in-progress 3203 (while python-shell-output-filter-in-progress
3186 ;; `python-shell-output-filter' takes care of setting 3204 ;; `python-shell-output-filter' takes care of setting
3187 ;; `python-shell-output-filter-in-progress' to NIL after it 3205 ;; `python-shell-output-filter-in-progress' to NIL after it
@@ -3378,18 +3396,6 @@ t when called interactively."
3378 nil ;; noop 3396 nil ;; noop
3379 msg)))) 3397 msg))))
3380 3398
3381
3382(defconst python-shell-eval-file-setup-code
3383 "\
3384def __PYTHON_EL_eval_file(filename, tempname, encoding, delete):
3385 import codecs, os
3386 with codecs.open(tempname or filename, encoding=encoding) as file:
3387 source = file.read().encode(encoding)
3388 if delete and tempname:
3389 os.remove(tempname)
3390 return __PYTHON_EL_eval(source, filename)"
3391 "Code used to evaluate files in inferior Python processes.")
3392
3393(defun python-shell-send-file (file-name &optional process temp-file-name 3399(defun python-shell-send-file (file-name &optional process temp-file-name
3394 delete msg) 3400 delete msg)
3395 "Send FILE-NAME to inferior Python PROCESS. 3401 "Send FILE-NAME to inferior Python PROCESS.
@@ -3419,9 +3425,7 @@ t when called interactively."
3419 (comint-send-string 3425 (comint-send-string
3420 process 3426 process
3421 (format 3427 (format
3422 "exec(%s);exec(%s);__PYTHON_EL_eval_file(%s, %s, %s, %s)\n" 3428 "__PYTHON_EL_eval_file(%s, %s, %s, %s)\n"
3423 (python-shell--encode-string python-shell-eval-setup-code)
3424 (python-shell--encode-string python-shell-eval-file-setup-code)
3425 (python-shell--encode-string file-name) 3429 (python-shell--encode-string file-name)
3426 (python-shell--encode-string (or temp-file-name "")) 3430 (python-shell--encode-string (or temp-file-name ""))
3427 (python-shell--encode-string (symbol-name encoding)) 3431 (python-shell--encode-string (symbol-name encoding))