diff options
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 293 |
1 files changed, 167 insertions, 126 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 339f2403c26..1c0f105ceaa 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -180,6 +180,12 @@ | |||
| 180 | ;; shell so that relative imports work properly using the | 180 | ;; shell so that relative imports work properly using the |
| 181 | ;; `python-shell-package-enable' command. | 181 | ;; `python-shell-package-enable' command. |
| 182 | 182 | ||
| 183 | ;; Shell remote support: remote Python shells are started with the | ||
| 184 | ;; correct environment for files opened remotely through tramp, also | ||
| 185 | ;; respecting dir-local variables provided `enable-remote-dir-locals' | ||
| 186 | ;; is non-nil. The logic for this is transparently handled by the | ||
| 187 | ;; `python-shell-with-environment' macro. | ||
| 188 | |||
| 183 | ;; Shell syntax highlighting: when enabled current input in shell is | 189 | ;; Shell syntax highlighting: when enabled current input in shell is |
| 184 | ;; highlighted. The variable `python-shell-font-lock-enable' controls | 190 | ;; highlighted. The variable `python-shell-font-lock-enable' controls |
| 185 | ;; activation of this feature globally when shells are started. | 191 | ;; activation of this feature globally when shells are started. |
| @@ -255,6 +261,7 @@ | |||
| 255 | (require 'cl-lib) | 261 | (require 'cl-lib) |
| 256 | (require 'comint) | 262 | (require 'comint) |
| 257 | (require 'json) | 263 | (require 'json) |
| 264 | (require 'tramp-sh) | ||
| 258 | 265 | ||
| 259 | ;; Avoid compiler warnings | 266 | ;; Avoid compiler warnings |
| 260 | (defvar view-return-to-alist) | 267 | (defvar view-return-to-alist) |
| @@ -2001,6 +2008,77 @@ virtualenv." | |||
| 2001 | :type '(alist string) | 2008 | :type '(alist string) |
| 2002 | :group 'python) | 2009 | :group 'python) |
| 2003 | 2010 | ||
| 2011 | (defun python-shell-calculate-process-environment () | ||
| 2012 | "Calculate `process-environment' or `tramp-remote-process-environment'. | ||
| 2013 | Pre-appends `python-shell-process-environment', sets extra | ||
| 2014 | pythonpaths from `python-shell-extra-pythonpaths' and sets a few | ||
| 2015 | virtualenv related vars. If `default-directory' points to a | ||
| 2016 | remote machine, the returned value is intended for | ||
| 2017 | `tramp-remote-process-environment'." | ||
| 2018 | (let* ((remote-p (file-remote-p default-directory)) | ||
| 2019 | (process-environment (append | ||
| 2020 | python-shell-process-environment | ||
| 2021 | (if remote-p | ||
| 2022 | tramp-remote-process-environment | ||
| 2023 | process-environment) nil)) | ||
| 2024 | (virtualenv (if python-shell-virtualenv-root | ||
| 2025 | (directory-file-name python-shell-virtualenv-root) | ||
| 2026 | nil))) | ||
| 2027 | (when python-shell-unbuffered | ||
| 2028 | (setenv "PYTHONUNBUFFERED" "1")) | ||
| 2029 | (when python-shell-extra-pythonpaths | ||
| 2030 | (setenv "PYTHONPATH" (python-shell-calculate-pythonpath))) | ||
| 2031 | (if (not virtualenv) | ||
| 2032 | process-environment | ||
| 2033 | (setenv "PYTHONHOME" nil) | ||
| 2034 | (setenv "VIRTUAL_ENV" virtualenv)) | ||
| 2035 | process-environment)) | ||
| 2036 | |||
| 2037 | (defun python-shell-calculate-exec-path () | ||
| 2038 | "Calculate `exec-path' or `tramp-remote-path'. | ||
| 2039 | Pre-appends `python-shell-exec-path' and adds the binary | ||
| 2040 | directory for virtualenv if `python-shell-virtualenv-root' is | ||
| 2041 | set. If `default-directory' points to a remote machine, the | ||
| 2042 | returned value is intended for `tramp-remote-path'." | ||
| 2043 | (let ((path (append | ||
| 2044 | ;; Use nil as the tail so that the list is a full copy, | ||
| 2045 | ;; this is a paranoid safeguard for side-effects. | ||
| 2046 | python-shell-exec-path | ||
| 2047 | (if (file-remote-p default-directory) | ||
| 2048 | tramp-remote-path | ||
| 2049 | exec-path) | ||
| 2050 | nil))) | ||
| 2051 | (if (not python-shell-virtualenv-root) | ||
| 2052 | path | ||
| 2053 | (cons (expand-file-name "bin" python-shell-virtualenv-root) | ||
| 2054 | path)))) | ||
| 2055 | |||
| 2056 | (defmacro python-shell-with-environment (&rest body) | ||
| 2057 | "Modify shell environment during execution of BODY. | ||
| 2058 | Temporarily sets `process-environment' and `exec-path' during | ||
| 2059 | execution of body. If `default-directory' points to a remote | ||
| 2060 | machine then modifies `tramp-remote-process-environment' and | ||
| 2061 | `tramp-remote-path' instead." | ||
| 2062 | (declare (indent 0) (debug (body))) | ||
| 2063 | (let ((remote-p (file-remote-p default-directory))) | ||
| 2064 | `(let ((process-environment | ||
| 2065 | (if ,remote-p | ||
| 2066 | process-environment | ||
| 2067 | (python-shell-calculate-process-environment))) | ||
| 2068 | (tramp-remote-process-environment | ||
| 2069 | (if ,remote-p | ||
| 2070 | (python-shell-calculate-process-environment) | ||
| 2071 | tramp-remote-process-environment)) | ||
| 2072 | (exec-path | ||
| 2073 | (if ,remote-p | ||
| 2074 | (python-shell-calculate-exec-path) | ||
| 2075 | exec-path)) | ||
| 2076 | (tramp-remote-path | ||
| 2077 | (if ,remote-p | ||
| 2078 | (python-shell-calculate-exec-path) | ||
| 2079 | tramp-remote-path))) | ||
| 2080 | ,(macroexp-progn body)))) | ||
| 2081 | |||
| 2004 | (defvar python-shell--prompt-calculated-input-regexp nil | 2082 | (defvar python-shell--prompt-calculated-input-regexp nil |
| 2005 | "Calculated input prompt regexp for inferior python shell. | 2083 | "Calculated input prompt regexp for inferior python shell. |
| 2006 | Do not set this variable directly, instead use | 2084 | Do not set this variable directly, instead use |
| @@ -2023,69 +2101,68 @@ shows a warning with instructions to avoid hangs and returns nil. | |||
| 2023 | When `python-shell-prompt-detect-enabled' is nil avoids any | 2101 | When `python-shell-prompt-detect-enabled' is nil avoids any |
| 2024 | detection and just returns nil." | 2102 | detection and just returns nil." |
| 2025 | (when python-shell-prompt-detect-enabled | 2103 | (when python-shell-prompt-detect-enabled |
| 2026 | (let* ((process-environment (python-shell-calculate-process-environment)) | 2104 | (python-shell-with-environment |
| 2027 | (exec-path (python-shell-calculate-exec-path)) | 2105 | (let* ((code (concat |
| 2028 | (code (concat | 2106 | "import sys\n" |
| 2029 | "import sys\n" | 2107 | "ps = [getattr(sys, 'ps%s' % i, '') for i in range(1,4)]\n" |
| 2030 | "ps = [getattr(sys, 'ps%s' % i, '') for i in range(1,4)]\n" | 2108 | ;; JSON is built manually for compatibility |
| 2031 | ;; JSON is built manually for compatibility | 2109 | "ps_json = '\\n[\"%s\", \"%s\", \"%s\"]\\n' % tuple(ps)\n" |
| 2032 | "ps_json = '\\n[\"%s\", \"%s\", \"%s\"]\\n' % tuple(ps)\n" | 2110 | "print (ps_json)\n" |
| 2033 | "print (ps_json)\n" | 2111 | "sys.exit(0)\n")) |
| 2034 | "sys.exit(0)\n")) | 2112 | (output |
| 2035 | (output | 2113 | (with-temp-buffer |
| 2036 | (with-temp-buffer | 2114 | ;; TODO: improve error handling by using |
| 2037 | ;; TODO: improve error handling by using | 2115 | ;; `condition-case' and displaying the error message to |
| 2038 | ;; `condition-case' and displaying the error message to | 2116 | ;; the user in the no-prompts warning. |
| 2039 | ;; the user in the no-prompts warning. | 2117 | (ignore-errors |
| 2040 | (ignore-errors | 2118 | (let ((code-file (python-shell--save-temp-file code))) |
| 2041 | (let ((code-file (python-shell--save-temp-file code))) | 2119 | ;; Use `process-file' as it is remote-host friendly. |
| 2042 | ;; Use `process-file' as it is remote-host friendly. | 2120 | (process-file |
| 2043 | (process-file | 2121 | python-shell-interpreter |
| 2044 | python-shell-interpreter | 2122 | code-file |
| 2045 | code-file | 2123 | '(t nil) |
| 2046 | '(t nil) | 2124 | nil |
| 2047 | nil | 2125 | python-shell-interpreter-interactive-arg) |
| 2048 | python-shell-interpreter-interactive-arg) | 2126 | ;; Try to cleanup |
| 2049 | ;; Try to cleanup | 2127 | (delete-file code-file))) |
| 2050 | (delete-file code-file))) | 2128 | (buffer-string))) |
| 2051 | (buffer-string))) | 2129 | (prompts |
| 2052 | (prompts | 2130 | (catch 'prompts |
| 2053 | (catch 'prompts | 2131 | (dolist (line (split-string output "\n" t)) |
| 2054 | (dolist (line (split-string output "\n" t)) | 2132 | (let ((res |
| 2055 | (let ((res | 2133 | ;; Check if current line is a valid JSON array |
| 2056 | ;; Check if current line is a valid JSON array | 2134 | (and (string= (substring line 0 2) "[\"") |
| 2057 | (and (string= (substring line 0 2) "[\"") | 2135 | (ignore-errors |
| 2058 | (ignore-errors | 2136 | ;; Return prompts as a list, not vector |
| 2059 | ;; Return prompts as a list, not vector | 2137 | (append (json-read-from-string line) nil))))) |
| 2060 | (append (json-read-from-string line) nil))))) | 2138 | ;; The list must contain 3 strings, where the first |
| 2061 | ;; The list must contain 3 strings, where the first | 2139 | ;; is the input prompt, the second is the block |
| 2062 | ;; is the input prompt, the second is the block | 2140 | ;; prompt and the last one is the output prompt. The |
| 2063 | ;; prompt and the last one is the output prompt. The | 2141 | ;; input prompt is the only one that can't be empty. |
| 2064 | ;; input prompt is the only one that can't be empty. | 2142 | (when (and (= (length res) 3) |
| 2065 | (when (and (= (length res) 3) | 2143 | (cl-every #'stringp res) |
| 2066 | (cl-every #'stringp res) | 2144 | (not (string= (car res) ""))) |
| 2067 | (not (string= (car res) ""))) | 2145 | (throw 'prompts res)))) |
| 2068 | (throw 'prompts res)))) | 2146 | nil))) |
| 2069 | nil))) | 2147 | (when (and (not prompts) |
| 2070 | (when (and (not prompts) | 2148 | python-shell-prompt-detect-failure-warning) |
| 2071 | python-shell-prompt-detect-failure-warning) | 2149 | (lwarn |
| 2072 | (lwarn | 2150 | '(python python-shell-prompt-regexp) |
| 2073 | '(python python-shell-prompt-regexp) | 2151 | :warning |
| 2074 | :warning | 2152 | (concat |
| 2075 | (concat | 2153 | "Python shell prompts cannot be detected.\n" |
| 2076 | "Python shell prompts cannot be detected.\n" | 2154 | "If your emacs session hangs when starting python shells\n" |
| 2077 | "If your emacs session hangs when starting python shells\n" | 2155 | "recover with `keyboard-quit' and then try fixing the\n" |
| 2078 | "recover with `keyboard-quit' and then try fixing the\n" | 2156 | "interactive flag for your interpreter by adjusting the\n" |
| 2079 | "interactive flag for your interpreter by adjusting the\n" | 2157 | "`python-shell-interpreter-interactive-arg' or add regexps\n" |
| 2080 | "`python-shell-interpreter-interactive-arg' or add regexps\n" | 2158 | "matching shell prompts in the directory-local friendly vars:\n" |
| 2081 | "matching shell prompts in the directory-local friendly vars:\n" | 2159 | " + `python-shell-prompt-regexp'\n" |
| 2082 | " + `python-shell-prompt-regexp'\n" | 2160 | " + `python-shell-prompt-block-regexp'\n" |
| 2083 | " + `python-shell-prompt-block-regexp'\n" | 2161 | " + `python-shell-prompt-output-regexp'\n" |
| 2084 | " + `python-shell-prompt-output-regexp'\n" | 2162 | "Or alternatively in:\n" |
| 2085 | "Or alternatively in:\n" | 2163 | " + `python-shell-prompt-input-regexps'\n" |
| 2086 | " + `python-shell-prompt-input-regexps'\n" | 2164 | " + `python-shell-prompt-output-regexps'"))) |
| 2087 | " + `python-shell-prompt-output-regexps'"))) | 2165 | prompts)))) |
| 2088 | prompts))) | ||
| 2089 | 2166 | ||
| 2090 | (defun python-shell-prompt-validate-regexps () | 2167 | (defun python-shell-prompt-validate-regexps () |
| 2091 | "Validate all user provided regexps for prompts. | 2168 | "Validate all user provided regexps for prompts. |
| @@ -2181,14 +2258,12 @@ the `buffer-name'." | |||
| 2181 | 2258 | ||
| 2182 | (defun python-shell-calculate-command () | 2259 | (defun python-shell-calculate-command () |
| 2183 | "Calculate the string used to execute the inferior Python process." | 2260 | "Calculate the string used to execute the inferior Python process." |
| 2184 | (let ((exec-path (python-shell-calculate-exec-path))) | 2261 | (python-shell-with-environment |
| 2185 | ;; `exec-path' gets tweaked so that virtualenv's specific | 2262 | ;; `exec-path' gets tweaked so that virtualenv's specific |
| 2186 | ;; `python-shell-interpreter' absolute path can be found by | 2263 | ;; `python-shell-interpreter' absolute path can be found by |
| 2187 | ;; `executable-find'. | 2264 | ;; `executable-find'. |
| 2188 | (format "%s %s" | 2265 | (format "%s %s" |
| 2189 | ;; FIXME: Why executable-find? | 2266 | (shell-quote-argument python-shell-interpreter) |
| 2190 | (shell-quote-argument | ||
| 2191 | (executable-find python-shell-interpreter)) | ||
| 2192 | python-shell-interpreter-args))) | 2267 | python-shell-interpreter-args))) |
| 2193 | 2268 | ||
| 2194 | (define-obsolete-function-alias | 2269 | (define-obsolete-function-alias |
| @@ -2205,38 +2280,6 @@ the `buffer-name'." | |||
| 2205 | (concat extra path-separator pythonpath) | 2280 | (concat extra path-separator pythonpath) |
| 2206 | extra))) | 2281 | extra))) |
| 2207 | 2282 | ||
| 2208 | (defun python-shell-calculate-process-environment () | ||
| 2209 | "Calculate process environment given `python-shell-virtualenv-root'." | ||
| 2210 | (let ((process-environment (append | ||
| 2211 | python-shell-process-environment | ||
| 2212 | process-environment nil)) | ||
| 2213 | (virtualenv (if python-shell-virtualenv-root | ||
| 2214 | (directory-file-name python-shell-virtualenv-root) | ||
| 2215 | nil))) | ||
| 2216 | (when python-shell-unbuffered | ||
| 2217 | (setenv "PYTHONUNBUFFERED" "1")) | ||
| 2218 | (when python-shell-extra-pythonpaths | ||
| 2219 | (setenv "PYTHONPATH" (python-shell-calculate-pythonpath))) | ||
| 2220 | (if (not virtualenv) | ||
| 2221 | process-environment | ||
| 2222 | (setenv "PYTHONHOME" nil) | ||
| 2223 | (setenv "PATH" (format "%s/bin%s%s" | ||
| 2224 | virtualenv path-separator | ||
| 2225 | (or (getenv "PATH") ""))) | ||
| 2226 | (setenv "VIRTUAL_ENV" virtualenv)) | ||
| 2227 | process-environment)) | ||
| 2228 | |||
| 2229 | (defun python-shell-calculate-exec-path () | ||
| 2230 | "Calculate exec path given `python-shell-virtualenv-root'." | ||
| 2231 | (let ((path (append | ||
| 2232 | ;; Use nil as the tail so that the list is a full copy, | ||
| 2233 | ;; this is a paranoid safeguard for side-effects. | ||
| 2234 | python-shell-exec-path exec-path nil))) | ||
| 2235 | (if (not python-shell-virtualenv-root) | ||
| 2236 | path | ||
| 2237 | (cons (expand-file-name "bin" python-shell-virtualenv-root) | ||
| 2238 | path)))) | ||
| 2239 | |||
| 2240 | (defvar python-shell--package-depth 10) | 2283 | (defvar python-shell--package-depth 10) |
| 2241 | 2284 | ||
| 2242 | (defun python-shell-package-enable (directory package) | 2285 | (defun python-shell-package-enable (directory package) |
| @@ -2561,31 +2604,30 @@ convention for temporary/internal buffers, and also makes sure | |||
| 2561 | the user is not queried for confirmation when the process is | 2604 | the user is not queried for confirmation when the process is |
| 2562 | killed." | 2605 | killed." |
| 2563 | (save-excursion | 2606 | (save-excursion |
| 2564 | (let* ((proc-buffer-name | 2607 | (python-shell-with-environment |
| 2565 | (format (if (not internal) "*%s*" " *%s*") proc-name)) | 2608 | (let* ((proc-buffer-name |
| 2566 | (process-environment (python-shell-calculate-process-environment)) | 2609 | (format (if (not internal) "*%s*" " *%s*") proc-name))) |
| 2567 | (exec-path (python-shell-calculate-exec-path))) | 2610 | (when (not (comint-check-proc proc-buffer-name)) |
| 2568 | (when (not (comint-check-proc proc-buffer-name)) | 2611 | (let* ((cmdlist (split-string-and-unquote cmd)) |
| 2569 | (let* ((cmdlist (split-string-and-unquote cmd)) | 2612 | (interpreter (car cmdlist)) |
| 2570 | (interpreter (car cmdlist)) | 2613 | (args (cdr cmdlist)) |
| 2571 | (args (cdr cmdlist)) | 2614 | (buffer (apply #'make-comint-in-buffer proc-name proc-buffer-name |
| 2572 | (buffer (apply #'make-comint-in-buffer proc-name proc-buffer-name | 2615 | interpreter nil args)) |
| 2573 | interpreter nil args)) | 2616 | (python-shell--parent-buffer (current-buffer)) |
| 2574 | (python-shell--parent-buffer (current-buffer)) | 2617 | (process (get-buffer-process buffer)) |
| 2575 | (process (get-buffer-process buffer)) | 2618 | ;; Users can override the interpreter and args |
| 2576 | ;; Users can override the interpreter and args | 2619 | ;; interactively when calling `run-python', let-binding |
| 2577 | ;; interactively when calling `run-python', let-binding | 2620 | ;; these allows to have the new right values in all |
| 2578 | ;; these allows to have the new right values in all | 2621 | ;; setup code that is done in `inferior-python-mode', |
| 2579 | ;; setup code that is done in `inferior-python-mode', | 2622 | ;; which is important, especially for prompt detection. |
| 2580 | ;; which is important, especially for prompt detection. | 2623 | (python-shell--interpreter interpreter) |
| 2581 | (python-shell--interpreter interpreter) | 2624 | (python-shell--interpreter-args |
| 2582 | (python-shell--interpreter-args | 2625 | (mapconcat #'identity args " "))) |
| 2583 | (mapconcat #'identity args " "))) | 2626 | (with-current-buffer buffer |
| 2584 | (with-current-buffer buffer | 2627 | (inferior-python-mode)) |
| 2585 | (inferior-python-mode)) | 2628 | (when show (display-buffer buffer)) |
| 2586 | (when show (display-buffer buffer)) | 2629 | (and internal (set-process-query-on-exit-flag process nil)))) |
| 2587 | (and internal (set-process-query-on-exit-flag process nil)))) | 2630 | proc-buffer-name)))) |
| 2588 | proc-buffer-name))) | ||
| 2589 | 2631 | ||
| 2590 | ;;;###autoload | 2632 | ;;;###autoload |
| 2591 | (defun run-python (&optional cmd dedicated show) | 2633 | (defun run-python (&optional cmd dedicated show) |
| @@ -3984,8 +4026,7 @@ See `python-check-command' for the default." | |||
| 3984 | ""))))))) | 4026 | ""))))))) |
| 3985 | (setq python-check-custom-command command) | 4027 | (setq python-check-custom-command command) |
| 3986 | (save-some-buffers (not compilation-ask-about-save) nil) | 4028 | (save-some-buffers (not compilation-ask-about-save) nil) |
| 3987 | (let ((process-environment (python-shell-calculate-process-environment)) | 4029 | (python-shell-with-environment |
| 3988 | (exec-path (python-shell-calculate-exec-path))) | ||
| 3989 | (compilation-start command nil | 4030 | (compilation-start command nil |
| 3990 | (lambda (_modename) | 4031 | (lambda (_modename) |
| 3991 | (format python-check-buffer-name command))))) | 4032 | (format python-check-buffer-name command))))) |