diff options
| author | Fabián Ezequiel Gallina | 2014-07-20 15:12:30 -0300 |
|---|---|---|
| committer | Fabián Ezequiel Gallina | 2014-07-20 15:12:30 -0300 |
| commit | b06a0dff84b2ec6b32e5740c17d595f6874e884f (patch) | |
| tree | e5d930815db4de04d665780e1a0979b2a147efc3 | |
| parent | 880b716696b4d8737e7199d6487f17b7e6825dd4 (diff) | |
| download | emacs-b06a0dff84b2ec6b32e5740c17d595f6874e884f.tar.gz emacs-b06a0dff84b2ec6b32e5740c17d595f6874e884f.zip | |
Make python.el work with IPython automatically.
* lisp/progmodes/python.el:
(python-shell-completion-setup-code): New value supporting iPython.
(python-shell-completion-string-code): New value supporting iPython.
(python-shell-completion-get-completions): Use them.
(python-shell-completion-module-string-code): Make obsolete.
(python-shell-prompt-input-regexps)
(python-shell-prompt-output-regexps): Add safeguard for ipdb.
(python-shell-output-filter): Fix comment typo.
* test/automated/python-tests.el:
(python-util-clone-local-variables-1): Fix test.
Fixes: debbugs:15510
| -rw-r--r-- | etc/NEWS | 17 | ||||
| -rw-r--r-- | lisp/ChangeLog | 12 | ||||
| -rw-r--r-- | lisp/progmodes/python.el | 206 | ||||
| -rw-r--r-- | test/ChangeLog | 5 | ||||
| -rw-r--r-- | test/automated/python-tests.el | 2 |
5 files changed, 138 insertions, 104 deletions
| @@ -670,6 +670,23 @@ display a "Homepage" header.) | |||
| 670 | ** In Prolog mode, `prolog-use-smie' has been removed, | 670 | ** In Prolog mode, `prolog-use-smie' has been removed, |
| 671 | along with the non-SMIE indentation code. | 671 | along with the non-SMIE indentation code. |
| 672 | 672 | ||
| 673 | ** Python mode | ||
| 674 | |||
| 675 | *** Out of the box support for CPython, iPython and readline based shells. | ||
| 676 | **** `python-shell-completion-module-string-code` is no longer used. | ||
| 677 | |||
| 678 | *** Automatic shell prompt detection. | ||
| 679 | **** New user options: | ||
| 680 | ***** `python-shell-interpreter-interactive-arg`. | ||
| 681 | ***** `python-shell-prompt-detect-enabled`. | ||
| 682 | ***** `python-shell-prompt-detect-failure-warning`. | ||
| 683 | ***** `python-shell-prompt-input-regexps`. | ||
| 684 | ***** `python-shell-prompt-output-regexps`. | ||
| 685 | |||
| 686 | *** Python shell support for remote hosts via tramp. | ||
| 687 | |||
| 688 | *** Correct display of line numbers for code sent to the Python shell. | ||
| 689 | |||
| 673 | ** Remember | 690 | ** Remember |
| 674 | 691 | ||
| 675 | *** The new command `remember-notes' creates a buffer that is saved on exit. | 692 | *** The new command `remember-notes' creates a buffer that is saved on exit. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 437b2225ce1..100d57f3893 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,15 @@ | |||
| 1 | 2014-07-20 Fabián Ezequiel Gallina <fgallina@gnu.org> | ||
| 2 | |||
| 3 | Make python.el work with IPython automatically. (Bug#15510) | ||
| 4 | * progmodes/python.el: | ||
| 5 | (python-shell-completion-setup-code): New value supporting iPython. | ||
| 6 | (python-shell-completion-string-code): New value supporting iPython. | ||
| 7 | (python-shell-completion-get-completions): Use them. | ||
| 8 | (python-shell-completion-module-string-code): Make obsolete. | ||
| 9 | (python-shell-prompt-input-regexps) | ||
| 10 | (python-shell-prompt-output-regexps): Add safeguard for ipdb. | ||
| 11 | (python-shell-output-filter): Fix comment typo. | ||
| 12 | |||
| 1 | 2014-07-19 Fabián Ezequiel Gallina <fgallina@gnu.org> | 13 | 2014-07-19 Fabián Ezequiel Gallina <fgallina@gnu.org> |
| 2 | 14 | ||
| 3 | Fix Python shell prompts detection for remote hosts. | 15 | Fix Python shell prompts detection for remote hosts. |
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 870640e4c55..229874d3d51 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -62,16 +62,46 @@ | |||
| 62 | ;; (add-hook 'python-mode-hook | 62 | ;; (add-hook 'python-mode-hook |
| 63 | ;; (lambda () (setq forward-sexp-function nil))) | 63 | ;; (lambda () (setq forward-sexp-function nil))) |
| 64 | 64 | ||
| 65 | ;; Shell interaction: is provided and allows you to easily execute any | 65 | ;; Shell interaction: is provided and allows opening Python shells |
| 66 | ;; block of code of your current buffer in an inferior Python process. | 66 | ;; inside Emacs and executing any block of code of your current buffer |
| 67 | ;; This relies upon having prompts for input (e.g. ">>> " and "... " | 67 | ;; in that inferior Python process. |
| 68 | ;; in standard Python shell) and output (e.g. "Out[1]: " in iPython) | 68 | |
| 69 | ;; detected properly. Failing that Emacs may hang but, in the case | 69 | ;; Besides that only the standard CPython (2.x and 3.x) shell and |
| 70 | ;; that happens, you can recover with \\[keyboard-quit]. To avoid | 70 | ;; IPython are officially supported out of the box, the interaction |
| 71 | ;; this issue, a two-step prompt autodetection mechanism is provided: | 71 | ;; should support any other readline based Python shells as well |
| 72 | ;; the first step is manual and consists of a collection of regular | 72 | ;; (e.g. Jython and Pypy have been reported to work). You can change |
| 73 | ;; expressions matching common prompts for Python shells stored in | 73 | ;; your default interpreter and commandline arguments by setting the |
| 74 | ;; `python-shell-prompt-input-regexps' and | 74 | ;; `python-shell-interpreter' and `python-shell-interpreter-args' |
| 75 | ;; variables. This example enables IPython globally: | ||
| 76 | |||
| 77 | ;; (setq python-shell-interpreter "ipython" | ||
| 78 | ;; python-shell-interpreter-args "-i") | ||
| 79 | |||
| 80 | ;; Using the "console" subcommand to start IPython in server-client | ||
| 81 | ;; mode is known to fail intermittently due a bug on IPython itself | ||
| 82 | ;; (see URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=18052#27'). | ||
| 83 | ;; There seems to be a race condition in the IPython server (A.K.A | ||
| 84 | ;; kernel) when code is sent while it is still initializing, sometimes | ||
| 85 | ;; causing the shell to get stalled. With that said, if an IPython | ||
| 86 | ;; kernel is already running, "console --existing" seems to work fine. | ||
| 87 | |||
| 88 | ;; Running IPython on Windows needs more tweaking. The way you should | ||
| 89 | ;; set `python-shell-interpreter' and `python-shell-interpreter-args' | ||
| 90 | ;; is as follows (of course you need to modify the paths according to | ||
| 91 | ;; your system): | ||
| 92 | |||
| 93 | ;; (setq python-shell-interpreter "C:\\Python27\\python.exe" | ||
| 94 | ;; python-shell-interpreter-args | ||
| 95 | ;; "-i C:\\Python27\\Scripts\\ipython-script.py") | ||
| 96 | |||
| 97 | ;; The interaction relies upon having prompts for input (e.g. ">>> " | ||
| 98 | ;; and "... " in standard Python shell) and output (e.g. "Out[1]: " in | ||
| 99 | ;; IPython) detected properly. Failing that Emacs may hang but, in | ||
| 100 | ;; the case that happens, you can recover with \\[keyboard-quit]. To | ||
| 101 | ;; avoid this issue, a two-step prompt autodetection mechanism is | ||
| 102 | ;; provided: the first step is manual and consists of a collection of | ||
| 103 | ;; regular expressions matching common prompts for Python shells | ||
| 104 | ;; stored in `python-shell-prompt-input-regexps' and | ||
| 75 | ;; `python-shell-prompt-output-regexps', and dir-local friendly vars | 105 | ;; `python-shell-prompt-output-regexps', and dir-local friendly vars |
| 76 | ;; `python-shell-prompt-regexp', `python-shell-prompt-block-regexp', | 106 | ;; `python-shell-prompt-regexp', `python-shell-prompt-block-regexp', |
| 77 | ;; `python-shell-prompt-output-regexp' which are appended to the | 107 | ;; `python-shell-prompt-output-regexp' which are appended to the |
| @@ -81,51 +111,23 @@ | |||
| 81 | ;; modify its behavior. | 111 | ;; modify its behavior. |
| 82 | 112 | ||
| 83 | ;; Shell completion: hitting tab will try to complete the current | 113 | ;; Shell completion: hitting tab will try to complete the current |
| 84 | ;; word. Shell completion is implemented in a way that if you change | 114 | ;; word. Shell completion is implemented in such way that if you |
| 85 | ;; the `python-shell-interpreter' to any other (for example IPython) | 115 | ;; change the `python-shell-interpreter' it should be possible to |
| 86 | ;; it should be easy to integrate another way to calculate | 116 | ;; integrate custom logic to calculate completions. To achieve this |
| 87 | ;; completions. You just need to specify your custom | 117 | ;; you just need to set `python-shell-completion-setup-code' and |
| 88 | ;; `python-shell-completion-setup-code' and | 118 | ;; `python-shell-completion-string-code'. The default provided code, |
| 89 | ;; `python-shell-completion-string-code'. | 119 | ;; enables autocompletion for both CPython and IPython (and ideally |
| 90 | 120 | ;; any readline based Python shell). This code depends on the | |
| 91 | ;; Here is a complete example of the settings you would use for | ||
| 92 | ;; iPython 0.11: | ||
| 93 | |||
| 94 | ;; (setq | ||
| 95 | ;; python-shell-interpreter "ipython" | ||
| 96 | ;; python-shell-interpreter-args "" | ||
| 97 | ;; python-shell-completion-setup-code | ||
| 98 | ;; "from IPython.core.completerlib import module_completion" | ||
| 99 | ;; python-shell-completion-module-string-code | ||
| 100 | ;; "';'.join(module_completion('''%s'''))\n" | ||
| 101 | ;; python-shell-completion-string-code | ||
| 102 | ;; "';'.join(get_ipython().Completer.all_completions('''%s'''))\n") | ||
| 103 | |||
| 104 | ;; For iPython 0.10 everything would be the same except for | ||
| 105 | ;; `python-shell-completion-string-code' and | ||
| 106 | ;; `python-shell-completion-module-string-code': | ||
| 107 | |||
| 108 | ;; (setq python-shell-completion-string-code | ||
| 109 | ;; "';'.join(__IP.complete('''%s'''))\n" | ||
| 110 | ;; python-shell-completion-module-string-code "") | ||
| 111 | |||
| 112 | ;; Unfortunately running iPython on Windows needs some more tweaking. | ||
| 113 | ;; The way you must set `python-shell-interpreter' and | ||
| 114 | ;; `python-shell-interpreter-args' is as follows: | ||
| 115 | |||
| 116 | ;; (setq | ||
| 117 | ;; python-shell-interpreter "C:\\Python27\\python.exe" | ||
| 118 | ;; python-shell-interpreter-args | ||
| 119 | ;; "-i C:\\Python27\\Scripts\\ipython-script.py") | ||
| 120 | |||
| 121 | ;; That will spawn the iPython process correctly (Of course you need | ||
| 122 | ;; to modify the paths according to your system). | ||
| 123 | |||
| 124 | ;; Please note that the default completion system depends on the | ||
| 125 | ;; readline module, so if you are using some Operating System that | 121 | ;; readline module, so if you are using some Operating System that |
| 126 | ;; bundles Python without it (like Windows) just install the | 122 | ;; bundles Python without it (like Windows), installing pyreadline |
| 127 | ;; pyreadline from http://ipython.scipy.org/moin/PyReadline/Intro and | 123 | ;; from URL `http://ipython.scipy.org/moin/PyReadline/Intro' should |
| 128 | ;; you should be good to go. | 124 | ;; suffice. To troubleshoot why you are not getting any completions |
| 125 | ;; you can try the following in your Python shell: | ||
| 126 | |||
| 127 | ;; >>> import readline, rlcompleter | ||
| 128 | |||
| 129 | ;; If you see an error, then you need to either install pyreadline or | ||
| 130 | ;; setup custom code that avoids that dependency. | ||
| 129 | 131 | ||
| 130 | ;; Shell virtualenv support: The shell also contains support for | 132 | ;; Shell virtualenv support: The shell also contains support for |
| 131 | ;; virtualenvs and other special environment modifications thanks to | 133 | ;; virtualenvs and other special environment modifications thanks to |
| @@ -1740,14 +1742,18 @@ position, else returns nil." | |||
| 1740 | 1742 | ||
| 1741 | (defcustom python-shell-prompt-input-regexps | 1743 | (defcustom python-shell-prompt-input-regexps |
| 1742 | '(">>> " "\\.\\.\\. " ; Python | 1744 | '(">>> " "\\.\\.\\. " ; Python |
| 1743 | "In \\[[0-9]+\\]: ") ; iPython | 1745 | "In \\[[0-9]+\\]: " ; IPython |
| 1746 | ;; Using ipdb outside IPython may fail to cleanup and leave static | ||
| 1747 | ;; IPython prompts activated, this adds some safeguard for that. | ||
| 1748 | "In : " "\\.\\.\\.: ") | ||
| 1744 | "List of regular expressions matching input prompts." | 1749 | "List of regular expressions matching input prompts." |
| 1745 | :type '(repeat string) | 1750 | :type '(repeat string) |
| 1746 | :version "24.4") | 1751 | :version "24.4") |
| 1747 | 1752 | ||
| 1748 | (defcustom python-shell-prompt-output-regexps | 1753 | (defcustom python-shell-prompt-output-regexps |
| 1749 | '("" ; Python | 1754 | '("" ; Python |
| 1750 | "Out\\[[0-9]+\\]: ") ; iPython | 1755 | "Out\\[[0-9]+\\]: " ; IPython |
| 1756 | "Out :") ; ipdb safeguard | ||
| 1751 | "List of regular expressions matching output prompts." | 1757 | "List of regular expressions matching output prompts." |
| 1752 | :type '(repeat string) | 1758 | :type '(repeat string) |
| 1753 | :version "24.4") | 1759 | :version "24.4") |
| @@ -2398,7 +2404,7 @@ detecting a prompt at the end of the buffer." | |||
| 2398 | (when (string-match | 2404 | (when (string-match |
| 2399 | python-shell--prompt-calculated-output-regexp | 2405 | python-shell--prompt-calculated-output-regexp |
| 2400 | python-shell-output-filter-buffer) | 2406 | python-shell-output-filter-buffer) |
| 2401 | ;; Some shells, like iPython might append a prompt before the | 2407 | ;; Some shells, like IPython might append a prompt before the |
| 2402 | ;; output, clean that. | 2408 | ;; output, clean that. |
| 2403 | (setq python-shell-output-filter-buffer | 2409 | (setq python-shell-output-filter-buffer |
| 2404 | (substring python-shell-output-filter-buffer (match-end 0))))) | 2410 | (substring python-shell-output-filter-buffer (match-end 0))))) |
| @@ -2608,23 +2614,35 @@ This function takes the list of setup code to send from the | |||
| 2608 | 2614 | ||
| 2609 | (defcustom python-shell-completion-setup-code | 2615 | (defcustom python-shell-completion-setup-code |
| 2610 | "try: | 2616 | "try: |
| 2611 | import readline | 2617 | import readline, rlcompleter |
| 2612 | except ImportError: | 2618 | except ImportError: |
| 2613 | def __COMPLETER_all_completions(text): [] | 2619 | def __PYTHON_EL_get_completions(text): |
| 2620 | return [] | ||
| 2614 | else: | 2621 | else: |
| 2615 | import rlcompleter | 2622 | def __PYTHON_EL_get_completions(text): |
| 2616 | readline.set_completer(rlcompleter.Completer().complete) | ||
| 2617 | def __COMPLETER_all_completions(text): | ||
| 2618 | import sys | ||
| 2619 | completions = [] | 2623 | completions = [] |
| 2620 | try: | 2624 | try: |
| 2621 | i = 0 | 2625 | splits = text.split() |
| 2622 | while True: | 2626 | is_module = splits and splits[0] in ('from', 'import') |
| 2623 | res = readline.get_completer()(text, i) | 2627 | is_ipython = getattr( |
| 2624 | if not res: break | 2628 | __builtins__, '__IPYTHON__', |
| 2625 | i += 1 | 2629 | getattr(__builtins__, '__IPYTHON__active', False)) |
| 2626 | completions.append(res) | 2630 | if is_module: |
| 2627 | except NameError: | 2631 | from IPython.core.completerlib import module_completion |
| 2632 | completions = module_completion(text.strip()) | ||
| 2633 | elif is_ipython and getattr(__builtins__, '__IP', None): | ||
| 2634 | completions = __IP.complete(text) | ||
| 2635 | elif is_ipython and getattr(__builtins__, 'get_ipython', None): | ||
| 2636 | completions = get_ipython().Completer.all_completions(text) | ||
| 2637 | else: | ||
| 2638 | i = 0 | ||
| 2639 | while True: | ||
| 2640 | res = readline.get_completer()(text, i) | ||
| 2641 | if not res: | ||
| 2642 | break | ||
| 2643 | i += 1 | ||
| 2644 | completions.append(res) | ||
| 2645 | except: | ||
| 2628 | pass | 2646 | pass |
| 2629 | return completions" | 2647 | return completions" |
| 2630 | "Code used to setup completion in inferior Python processes." | 2648 | "Code used to setup completion in inferior Python processes." |
| @@ -2632,24 +2650,18 @@ else: | |||
| 2632 | :group 'python) | 2650 | :group 'python) |
| 2633 | 2651 | ||
| 2634 | (defcustom python-shell-completion-string-code | 2652 | (defcustom python-shell-completion-string-code |
| 2635 | "';'.join(__COMPLETER_all_completions('''%s'''))\n" | 2653 | "';'.join(__PYTHON_EL_get_completions('''%s'''))\n" |
| 2636 | "Python code used to get a string of completions separated by semicolons." | 2654 | "Python code used to get a string of completions separated by semicolons. |
| 2655 | The string passed to the function is the current python name or | ||
| 2656 | the full statement in the case of imports." | ||
| 2637 | :type 'string | 2657 | :type 'string |
| 2638 | :group 'python) | 2658 | :group 'python) |
| 2639 | 2659 | ||
| 2640 | (defcustom python-shell-completion-module-string-code "" | 2660 | (define-obsolete-variable-alias |
| 2641 | "Python code used to get completions separated by semicolons for imports. | 2661 | 'python-shell-completion-module-string-code |
| 2642 | 2662 | 'python-shell-completion-string-code | |
| 2643 | For IPython v0.11, add the following line to | 2663 | "24.4" |
| 2644 | `python-shell-completion-setup-code': | 2664 | "Completion string code must also autocomplete modules.") |
| 2645 | |||
| 2646 | from IPython.core.completerlib import module_completion | ||
| 2647 | |||
| 2648 | and use the following as the value of this variable: | ||
| 2649 | |||
| 2650 | ';'.join(module_completion('''%s'''))\n" | ||
| 2651 | :type 'string | ||
| 2652 | :group 'python) | ||
| 2653 | 2665 | ||
| 2654 | (defcustom python-shell-completion-pdb-string-code | 2666 | (defcustom python-shell-completion-pdb-string-code |
| 2655 | "';'.join(globals().keys() + locals().keys())" | 2667 | "';'.join(globals().keys() + locals().keys())" |
| @@ -2672,33 +2684,23 @@ LINE is used to detect the context on how to complete given INPUT." | |||
| 2672 | (re-search-backward "^") | 2684 | (re-search-backward "^") |
| 2673 | (python-util-forward-comment) | 2685 | (python-util-forward-comment) |
| 2674 | (point)))))) | 2686 | (point)))))) |
| 2675 | (completion-context | 2687 | (completion-code |
| 2676 | ;; Check whether a prompt matches a pdb string, an import | 2688 | ;; Check whether a prompt matches a pdb string, an import |
| 2677 | ;; statement or just the standard prompt and use the | 2689 | ;; statement or just the standard prompt and use the |
| 2678 | ;; correct python-shell-completion-*-code string | 2690 | ;; correct python-shell-completion-*-code string |
| 2679 | (cond ((and (> (length python-shell-completion-pdb-string-code) 0) | 2691 | (cond ((and (> (length python-shell-completion-pdb-string-code) 0) |
| 2680 | (string-match | 2692 | (string-match |
| 2681 | (concat "^" python-shell-prompt-pdb-regexp) prompt)) | 2693 | (concat "^" python-shell-prompt-pdb-regexp) prompt)) |
| 2682 | 'pdb) | 2694 | python-shell-completion-pdb-string-code) |
| 2683 | ((and (> | ||
| 2684 | (length python-shell-completion-module-string-code) 0) | ||
| 2685 | (string-match | ||
| 2686 | python-shell--prompt-calculated-input-regexp prompt) | ||
| 2687 | (string-match "^[ \t]*\\(from\\|import\\)[ \t]" line)) | ||
| 2688 | 'import) | ||
| 2689 | ((string-match | 2695 | ((string-match |
| 2690 | python-shell--prompt-calculated-input-regexp prompt) | 2696 | python-shell--prompt-calculated-input-regexp prompt) |
| 2691 | 'default) | 2697 | python-shell-completion-string-code) |
| 2692 | (t nil))) | 2698 | (t nil))) |
| 2693 | (completion-code | ||
| 2694 | (pcase completion-context | ||
| 2695 | (`pdb python-shell-completion-pdb-string-code) | ||
| 2696 | (`import python-shell-completion-module-string-code) | ||
| 2697 | (`default python-shell-completion-string-code) | ||
| 2698 | (_ nil))) | ||
| 2699 | (input | 2699 | (input |
| 2700 | (if (eq completion-context 'import) | 2700 | (if (string-match |
| 2701 | (replace-regexp-in-string "^[ \t]+" "" line) | 2701 | (python-rx (+ space) (or "from" "import") space) |
| 2702 | line) | ||
| 2703 | line | ||
| 2702 | input))) | 2704 | input))) |
| 2703 | (and completion-code | 2705 | (and completion-code |
| 2704 | (> (length input) 0) | 2706 | (> (length input) 0) |
diff --git a/test/ChangeLog b/test/ChangeLog index b4b3bedcbdc..451fa91548f 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2014-07-20 Fabián Ezequiel Gallina <fgallina@gnu.org> | ||
| 2 | |||
| 3 | * automated/python-tests.el: | ||
| 4 | (python-util-clone-local-variables-1): Fix test. | ||
| 5 | |||
| 1 | 2014-07-17 Fabián Ezequiel Gallina <fgallina@gnu.org> | 6 | 2014-07-17 Fabián Ezequiel Gallina <fgallina@gnu.org> |
| 2 | 7 | ||
| 3 | * automated/python-tests.el (python-shell-make-comint-1): | 8 | * automated/python-tests.el (python-shell-make-comint-1): |
diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index a60da31e44c..81f4567091e 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el | |||
| @@ -3619,8 +3619,6 @@ def foo(a, b, c): | |||
| 3619 | (python-shell-extra-pythonpaths "/home/user/pylib/") | 3619 | (python-shell-extra-pythonpaths "/home/user/pylib/") |
| 3620 | (python-shell-completion-setup-code | 3620 | (python-shell-completion-setup-code |
| 3621 | . "from IPython.core.completerlib import module_completion") | 3621 | . "from IPython.core.completerlib import module_completion") |
| 3622 | (python-shell-completion-module-string-code | ||
| 3623 | . "';'.join(module_completion('''%s'''))\n") | ||
| 3624 | (python-shell-completion-string-code | 3622 | (python-shell-completion-string-code |
| 3625 | . "';'.join(get_ipython().Completer.all_completions('''%s'''))\n") | 3623 | . "';'.join(get_ipython().Completer.all_completions('''%s'''))\n") |
| 3626 | (python-shell-virtualenv-path | 3624 | (python-shell-virtualenv-path |