From 238c052fdb9da3b1f96c09809461b70813c5bebc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabi=C3=A1n=20Ezequiel=20Gallina?= Date: Sat, 22 Nov 2014 20:09:30 -0300 Subject: [PATCH] Set PYTHONUNBUFFERED on shell startup. Fixes: debbugs:18595 * lisp/progmodes/python.el (python-shell-unbuffered): New var. (python-shell-calculate-process-environment): Use it. * test/automated/python-tests.el (python-shell-calculate-process-environment-4) (python-shell-calculate-process-environment-5): New tests. (python-shell-make-comint-3): Use file-equal-p. (python-shell-get-or-create-process-1) (python-shell-get-or-create-process-2) (python-shell-get-or-create-process-3): Fix interpreter for Windows. --- lisp/ChangeLog | 7 ++++ lisp/progmodes/python.el | 22 ++++++++--- test/ChangeLog | 11 ++++++ test/automated/python-tests.el | 89 ++++++++++++++++++++++++------------------ 4 files changed, 86 insertions(+), 43 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0f16eabdc03..e59c3910fd7 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2014-11-22 Fabián Ezequiel Gallina + + Set PYTHONUNBUFFERED on shell startup. + + * progmodes/python.el (python-shell-unbuffered): New var. + (python-shell-calculate-process-environment): Use it. + 2014-11-22 Michael Albinus * net/tramp.el (tramp-action-password): Clean password on subsequent diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 5a5a039afc9..4c27136f3b5 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -94,13 +94,13 @@ ;; python-shell-interpreter-args ;; "-i C:\\Python27\\Scripts\\ipython-script.py") -;; If you are experiencing missing or delayed output in your shells, -;; that's likely caused by your Operating System's pipe buffering -;; (e.g. this is known to happen running CPython 3.3.4 in Windows 7. +;; Missing or delayed output used to happen due to differences between +;; Operating Systems' pipe buffering (e.g. CPython 3.3.4 in Windows 7. ;; See URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17304'). To -;; fix this, using CPython's "-u" commandline argument or setting the -;; "PYTHONUNBUFFERED" environment variable should help: See URL -;; `https://docs.python.org/3/using/cmdline.html#cmdoption-u'. +;; avoid this, the `python-shell-unbuffered' defaults to non-nil and +;; controls whether `python-shell-calculate-process-environment' +;; should set the "PYTHONUNBUFFERED" environment variable on startup: +;; See URL `https://docs.python.org/3/using/cmdline.html#cmdoption-u'. ;; The interaction relies upon having prompts for input (e.g. ">>> " ;; and "... " in standard Python shell) and output (e.g. "Out[1]: " in @@ -1813,6 +1813,14 @@ Restart the Python shell after changing this variable for it to take effect." :group 'python :safe 'booleanp) +(defcustom python-shell-unbuffered t + "Should shell output be unbuffered?. +When non-nil, this may prevent delayed and missing output in the +Python shell. See commentary for details." + :type 'boolean + :group 'python + :safe 'booleanp) + (defcustom python-shell-process-environment nil "List of environment variables for Python shell. This variable follows the same rules as `process-environment' @@ -2087,6 +2095,8 @@ uniqueness for different types of configurations." (virtualenv (if python-shell-virtualenv-path (directory-file-name python-shell-virtualenv-path) nil))) + (when python-shell-unbuffered + (setenv "PYTHONUNBUFFERED" "1")) (when python-shell-extra-pythonpaths (setenv "PYTHONPATH" (format "%s%s%s" diff --git a/test/ChangeLog b/test/ChangeLog index 4f7f068e796..0da5f99b226 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,14 @@ +2014-11-22 Fabián Ezequiel Gallina + + * automated/python-tests.el + (python-shell-calculate-process-environment-4) + (python-shell-calculate-process-environment-5): New tests. + (python-shell-make-comint-3): Use file-equal-p. + (python-shell-get-or-create-process-1) + (python-shell-get-or-create-process-2) + (python-shell-get-or-create-process-3): Fix interpreter for + Windows (Bug#18595). + 2014-11-15 Fabián Ezequiel Gallina * automated/python-tests.el (python-indent-dedenters-8): New test diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index f368f995cae..f84ded8cad2 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el @@ -1872,6 +1872,23 @@ Using `python-shell-interpreter' and python-shell-virtualenv-path path-separator original-path))))) +(ert-deftest python-shell-calculate-process-environment-4 () + "Test `python-shell-unbuffered' modification." + (setenv "PYTHONUNBUFFERED") + (let* ((process-environment + (python-shell-calculate-process-environment))) + ;; Defaults to t + (should python-shell-unbuffered) + (should (string= (getenv "PYTHONUNBUFFERED") "1")))) + +(ert-deftest python-shell-calculate-process-environment-5 () + (setenv "PYTHONUNBUFFERED") + "Test `python-shell-unbuffered' modification." + (let* ((python-shell-unbuffered nil) + (process-environment + (python-shell-calculate-process-environment))) + (should (not (getenv "PYTHONUNBUFFERED"))))) + (ert-deftest python-shell-calculate-exec-path-1 () "Test `python-shell-exec-path' modification." (let* ((original-exec-path exec-path) @@ -1961,8 +1978,9 @@ and `python-shell-interpreter-args' in the new shell buffer." (should (process-live-p process)) (with-current-buffer shell-buffer (should (eq major-mode 'inferior-python-mode)) - (should (string= python-shell-interpreter - (executable-find python-tests-shell-interpreter))) + (should (file-equal-p + python-shell-interpreter + (executable-find python-tests-shell-interpreter))) (should (string= python-shell-interpreter-args "-i")))) (kill-buffer shell-buffer)))) @@ -2050,12 +2068,11 @@ and `python-shell-interpreter-args' in the new shell buffer." (skip-unless (executable-find python-tests-shell-interpreter)) (python-tests-with-temp-file "" - (let* ((python-shell-interpreter - (executable-find python-tests-shell-interpreter)) + (let* ((cmd + (concat (executable-find python-tests-shell-interpreter) " -i")) (use-dialog-box) (dedicated-process-name (python-shell-get-process-name t)) - (dedicated-process - (python-shell-get-or-create-process python-shell-interpreter t)) + (dedicated-process (python-shell-get-or-create-process cmd t)) (dedicated-shell-buffer (process-buffer dedicated-process))) (unwind-protect (progn @@ -2073,12 +2090,11 @@ and `python-shell-interpreter-args' in the new shell buffer." (skip-unless (executable-find python-tests-shell-interpreter)) (python-tests-with-temp-file "" - (let* ((python-shell-interpreter - (executable-find python-tests-shell-interpreter)) + (let* ((cmd + (concat (executable-find python-tests-shell-interpreter) " -i")) (use-dialog-box) (process-name (python-shell-get-process-name nil)) - (process - (python-shell-get-or-create-process python-shell-interpreter)) + (process (python-shell-get-or-create-process cmd)) (shell-buffer (process-buffer process))) (unwind-protect (progn @@ -2088,43 +2104,42 @@ and `python-shell-interpreter-args' in the new shell buffer." (kill-buffer shell-buffer) ;; Check there are no processes for current buffer. (should (not (python-shell-get-process)))) - (ignore-errors (kill-buffer dedicated-shell-buffer)))))) + (ignore-errors (kill-buffer shell-buffer)))))) (ert-deftest python-shell-get-or-create-process-3 () "Check shell dedicated/global process preference." (skip-unless (executable-find python-tests-shell-interpreter)) (python-tests-with-temp-file "" - (let* ((python-shell-interpreter - (executable-find python-tests-shell-interpreter)) + (let* ((cmd + (concat (executable-find python-tests-shell-interpreter) " -i")) + (python-shell-interpreter python-tests-shell-interpreter) (use-dialog-box) (dedicated-process-name (python-shell-get-process-name t)) (global-process) (dedicated-process)) - (unwind-protect - (progn - ;; Create global process - (run-python python-shell-interpreter nil) - (setq global-process (get-buffer-process "*Python*")) - (should global-process) - (set-process-query-on-exit-flag global-process nil) - ;; Create dedicated process - (run-python python-shell-interpreter t) - (setq dedicated-process (get-process dedicated-process-name)) - (should dedicated-process) - (set-process-query-on-exit-flag dedicated-process nil) - ;; Prefer dedicated. - (should (equal (python-shell-get-or-create-process) - dedicated-process)) - ;; Kill the dedicated so the global takes over. - (kill-buffer (process-buffer dedicated-process)) - ;; Detect global. - (should (equal (python-shell-get-or-create-process) global-process)) - ;; Kill the global. - (kill-buffer (process-buffer global-process)) - ;; Check there are no processes for current buffer. - (should (not (python-shell-get-process)))) - (ignore-errors (kill-buffer dedicated-shell-buffer)))))) + (progn + ;; Create global process + (run-python cmd nil) + (setq global-process (get-buffer-process "*Python*")) + (should global-process) + (set-process-query-on-exit-flag global-process nil) + ;; Create dedicated process + (run-python cmd t) + (setq dedicated-process (get-process dedicated-process-name)) + (should dedicated-process) + (set-process-query-on-exit-flag dedicated-process nil) + ;; Prefer dedicated. + (should (equal (python-shell-get-or-create-process) + dedicated-process)) + ;; Kill the dedicated so the global takes over. + (kill-buffer (process-buffer dedicated-process)) + ;; Detect global. + (should (equal (python-shell-get-or-create-process) global-process)) + ;; Kill the global. + (kill-buffer (process-buffer global-process)) + ;; Check there are no processes for current buffer. + (should (not (python-shell-get-process))))))) (ert-deftest python-shell-internal-get-or-create-process-1 () "Check internal shell process creation fallback." -- 2.11.4.GIT