;;; python.el --- Python's flying circus support for Emacs -*- lexical-binding: t -*-
-;; Copyright (C) 2003-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2003-2015 Free Software Foundation, Inc.
;; Author: Fabián E. Gallina <fabian@anue.biz>
;; URL: https://github.com/fgallina/python.el
;; Besides that only the standard CPython (2.x and 3.x) shell and
;; IPython are officially supported out of the box, the interaction
;; should support any other readline based Python shells as well
-;; (e.g. Jython and Pypy have been reported to work). You can change
+;; (e.g. Jython and PyPy have been reported to work). You can change
;; your default interpreter and commandline arguments by setting the
;; `python-shell-interpreter' and `python-shell-interpreter-args'
;; variables. This example enables IPython globally:
;; 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
;; modify its behavior.
;; Shell completion: hitting tab will try to complete the current
-;; word. Shell completion is implemented in such way that if you
-;; change the `python-shell-interpreter' it should be possible to
-;; integrate custom logic to calculate completions. To achieve this
-;; you just need to set `python-shell-completion-setup-code' and
-;; `python-shell-completion-string-code'. The default provided code,
-;; enables autocompletion for both CPython and IPython (and ideally
-;; any readline based Python shell). This code depends on the
-;; readline module, so if you are using some Operating System that
-;; bundles Python without it (like Windows), installing pyreadline
-;; from URL `http://ipython.scipy.org/moin/PyReadline/Intro' should
-;; suffice. To troubleshoot why you are not getting any completions
-;; you can try the following in your Python shell:
+;; word. The two built-in mechanisms depend on Python's readline
+;; module: the "native" completion is tried first and is activated
+;; when `python-shell-completion-native-enable' is non-nil, the
+;; current `python-shell-interpreter' is not a member of the
+;; `python-shell-completion-native-disabled-interpreters' variable and
+;; `python-shell-completion-native-setup' succeeds; the "fallback" or
+;; "legacy" mechanism works by executing Python code in the background
+;; and enables auto-completion for shells that do not support
+;; receiving escape sequences (with some limitations, i.e. completion
+;; in blocks does not work). The code executed for the "fallback"
+;; completion can be found in `python-shell-completion-setup-code' and
+;; `python-shell-completion-string-code' variables. Their default
+;; values enable completion for both CPython and IPython, and probably
+;; any readline based shell (it's known to work with PyPy). If your
+;; Python installation lacks readline (like CPython for Windows),
+;; installing pyreadline (URL `http://ipython.org/pyreadline.html')
+;; should suffice. To troubleshoot why you are not getting any
+;; completions, you can try the following in your Python shell:
;; >>> import readline, rlcompleter
;; (python-shell-exec-path . ("/path/to/env/bin/"))
;; Since the above is cumbersome and can be programmatically
-;; calculated, the variable `python-shell-virtualenv-path' is
+;; calculated, the variable `python-shell-virtualenv-root' is
;; provided. When this variable is set with the path of the
;; virtualenv to use, `process-environment' and `exec-path' get proper
;; values in order to run shells inside the specified virtualenv. So
;; the following will achieve the same as the previous example:
-;; (setq python-shell-virtualenv-path "/path/to/env/")
+;; (setq python-shell-virtualenv-root "/path/to/env/")
;; Also the `python-shell-extra-pythonpaths' variable have been
;; introduced as simple way of adding paths to the PYTHONPATH without
;; `python-imenu-format-parent-item-jump-label-function' variables for
;; changing the way labels are formatted in the tree version.
-;; If you used python-mode.el you probably will miss auto-indentation
-;; when inserting newlines. To achieve the same behavior you have
-;; two options:
+;; If you used python-mode.el you may miss auto-indentation when
+;; inserting newlines. To achieve the same behavior you have two
+;; options:
-;; 1) Use GNU/Emacs' standard binding for `newline-and-indent': C-j.
+;; 1) Enable the minor-mode `electric-indent-mode' (enabled by
+;; default) and use RET. If this mode is disabled use
+;; `newline-and-indent', bound to C-j.
;; 2) Add the following hook in your .emacs:
(defvar outline-heading-end-regexp)
(autoload 'comint-mode "comint")
+(autoload 'help-function-arglist "help-fns")
;;;###autoload
(add-to-list 'auto-mode-alist (cons (purecopy "\\.py\\'") 'python-mode))
(* ?\\ ?\\) (any ?\' ?\")))
(* ?\\ ?\\)
;; Match single or triple quotes of any kind.
- (group (or "\"" "\"\"\"" "'" "'''"))))))
+ (group (or "\"" "\"\"\"" "'" "'''")))))
+ (coding-cookie . ,(rx line-start ?# (* space)
+ (or
+ ;; # coding=<encoding name>
+ (: "coding" (or ?: ?=) (* space) (group-n 1 (+ (or word ?-))))
+ ;; # -*- coding: <encoding name> -*-
+ (: "-*-" (* space) "coding:" (* space)
+ (group-n 1 (+ (or word ?-))) (* space) "-*-")
+ ;; # vim: set fileencoding=<encoding name> :
+ (: "vim:" (* space) "set" (+ space)
+ "fileencoding" (* space) ?= (* space)
+ (group-n 1 (+ (or word ?-))) (* space) ":")))))
"Additional Python specific sexps for `python-rx'")
(defmacro python-rx (&rest regexps)
'python-info-ppss-comment-or-string-p
#'python-syntax-comment-or-string-p "24.3")
+(defun python-docstring-at-p (pos)
+ "Check to see if there is a docstring at POS."
+ (save-excursion
+ (goto-char pos)
+ (if (looking-at-p "'''\\|\"\"\"")
+ (progn
+ (python-nav-backward-statement)
+ (looking-at "\\`\\|class \\|def "))
+ nil)))
+
+(defun python-font-lock-syntactic-face-function (state)
+ (if (nth 3 state)
+ (if (python-docstring-at-p (nth 8 state))
+ font-lock-doc-face
+ font-lock-string-face)
+ font-lock-comment-face))
+
(defvar python-font-lock-keywords
;; Keywords
`(,(rx symbol-start
"Current indentation level `python-indent-line-function' is using.")
(defvar python-indent-levels '(0)
- "Levels of indentation available for `python-indent-line-function'.")
+ "Levels of indentation available for `python-indent-line-function'.
+Can also be `noindent' if automatic indentation can't be used.")
(defun python-indent-guess-indent-offset ()
"Guess and set `python-indent-offset' for the current buffer."
start))))
(defun python-indent-calculate-indentation ()
- "Calculate correct indentation offset for the current line."
+ "Calculate correct indentation offset for the current line.
+Returns `noindent' if the indentation does not depend on Python syntax,
+such as in strings."
(let* ((indentation-context (python-indent-context))
(context-status (car indentation-context))
(context-start (cdr indentation-context)))
;; When inside of a string, do nothing. just use the current
;; indentation. XXX: perhaps it would be a good idea to
;; invoke standard text indentation here
- (`inside-string
- (goto-char context-start)
- (current-indentation))
+ (`inside-string 'noindent)
;; After backslash we have several possibilities.
(`after-backslash
(cond
(defun python-indent-calculate-levels ()
"Calculate `python-indent-levels' and reset `python-indent-current-level'."
- (if (not (python-info-dedenter-statement-p))
- (let* ((indentation (python-indent-calculate-indentation))
- (remainder (% indentation python-indent-offset))
- (steps (/ (- indentation remainder) python-indent-offset)))
- (setq python-indent-levels (list 0))
- (dotimes (step steps)
- (push (* python-indent-offset (1+ step)) python-indent-levels))
- (when (not (eq 0 remainder))
- (push (+ (* python-indent-offset steps) remainder) python-indent-levels)))
+ (if (or (python-info-continuation-line-p)
+ (not (python-info-dedenter-statement-p)))
+ ;; XXX: This asks for a refactor. Even if point is on a
+ ;; dedenter statement, it could be multiline and in that case
+ ;; the continuation lines should be indented with normal rules.
+ (let* ((indentation (python-indent-calculate-indentation)))
+ (if (not (numberp indentation))
+ (setq python-indent-levels indentation)
+ (let* ((remainder (% indentation python-indent-offset))
+ (steps (/ (- indentation remainder) python-indent-offset)))
+ (setq python-indent-levels (list 0))
+ (dotimes (step steps)
+ (push (* python-indent-offset (1+ step)) python-indent-levels))
+ (when (not (eq 0 remainder))
+ (push (+ (* python-indent-offset steps) remainder)
+ python-indent-levels)))))
(setq python-indent-levels
(or
(mapcar (lambda (pos)
(current-indentation)))
(python-info-dedenter-opening-block-positions))
(list 0))))
- (setq python-indent-current-level (1- (length python-indent-levels))
- python-indent-levels (nreverse python-indent-levels)))
+ (when (listp python-indent-levels)
+ (setq python-indent-current-level (1- (length python-indent-levels))
+ python-indent-levels (nreverse python-indent-levels))))
(defun python-indent-toggle-levels ()
"Toggle `python-indent-current-level' over `python-indent-levels'."
variable `python-indent-current-level' correctly so offset is
equal to
(nth python-indent-current-level python-indent-levels)"
- (or
- (and (or (and (memq this-command python-indent-trigger-commands)
- (eq last-command this-command))
- force-toggle)
- (not (equal python-indent-levels '(0)))
- (or (python-indent-toggle-levels) t))
- (python-indent-calculate-levels))
- (let* ((starting-pos (point-marker))
- (indent-ending-position
- (+ (line-beginning-position) (current-indentation)))
- (follow-indentation-p
- (or (bolp)
- (and (<= (line-beginning-position) starting-pos)
- (>= indent-ending-position starting-pos))))
- (next-indent (nth python-indent-current-level python-indent-levels)))
- (unless (= next-indent (current-indentation))
- (beginning-of-line)
- (delete-horizontal-space)
- (indent-to next-indent)
- (goto-char starting-pos))
- (and follow-indentation-p (back-to-indentation)))
- (python-info-dedenter-opening-block-message))
+ (if (and (or (and (memq this-command python-indent-trigger-commands)
+ (eq last-command this-command))
+ force-toggle)
+ (not (equal python-indent-levels '(0))))
+ (if (listp python-indent-levels)
+ (python-indent-toggle-levels))
+ (python-indent-calculate-levels))
+ (if (eq python-indent-levels 'noindent)
+ python-indent-levels
+ (let* ((starting-pos (point-marker))
+ (indent-ending-position
+ (+ (line-beginning-position) (current-indentation)))
+ (follow-indentation-p
+ (or (bolp)
+ (and (<= (line-beginning-position) starting-pos)
+ (>= indent-ending-position starting-pos))))
+ (next-indent (nth python-indent-current-level python-indent-levels)))
+ (unless (= next-indent (current-indentation))
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (indent-to next-indent)
+ (goto-char starting-pos))
+ (and follow-indentation-p (back-to-indentation)))
+ (python-info-dedenter-opening-block-message)))
(defun python-indent-line-function ()
"`indent-line-function' for Python mode.
(or (bolp) (forward-line 1))
(while (< (point) end)
(or (and (bolp) (eolp))
- (let (word)
- (forward-line -1)
- (back-to-indentation)
- (setq word (current-word))
- (forward-line 1)
- (when (and word
- ;; Don't mess with strings, unless it's the
- ;; enclosing set of quotes.
- (or (not (python-syntax-context 'string))
- (eq
- (syntax-after
- (+ (1- (point))
- (current-indentation)
- (python-syntax-count-quotes (char-after) (point))))
- (string-to-syntax "|"))))
- (beginning-of-line)
- (delete-horizontal-space)
- (indent-to (python-indent-calculate-indentation)))))
+ (when (and
+ ;; Skip if previous line is empty or a comment.
+ (save-excursion
+ (let ((line-is-comment-p
+ (python-info-current-line-comment-p)))
+ (forward-line -1)
+ (not
+ (or (and (python-info-current-line-comment-p)
+ ;; Unless this line is a comment too.
+ (not line-is-comment-p))
+ (python-info-current-line-empty-p)))))
+ ;; Don't mess with strings, unless it's the
+ ;; enclosing set of quotes.
+ (or (not (python-syntax-context 'string))
+ (eq
+ (syntax-after
+ (+ (1- (point))
+ (current-indentation)
+ (python-syntax-count-quotes (char-after) (point))))
+ (string-to-syntax "|")))
+ ;; Skip if current line is a block start, a
+ ;; dedenter or block ender.
+ (save-excursion
+ (back-to-indentation)
+ (not (looking-at
+ (python-rx
+ (or block-start dedenter block-ender))))))
+ (python-indent-line)))
(forward-line 1))
(move-marker end nil))))
(save-excursion
(goto-char (line-beginning-position))
(let ((indentation (python-indent-calculate-indentation)))
- (when (< (current-indentation) indentation)
+ (when (and (numberp indentation) (< (current-indentation) indentation))
(indent-line-to indentation)))))
;; Electric colon
((and (eq ?: last-command-event)
(eolp)
;; Avoid re-indenting on extra colon
(not (equal ?: (char-before (1- (point)))))
- (not (python-syntax-comment-or-string-p))
- ;; Never re-indent at beginning of defun
- (not (save-excursion
- (python-nav-beginning-of-statement)
- (python-info-looking-at-beginning-of-defun))))
- (python-indent-line)))))
+ (not (python-syntax-comment-or-string-p)))
+ ;; Just re-indent dedenters
+ (let ((dedenter-pos (python-info-dedenter-statement-p))
+ (current-pos (point)))
+ (when dedenter-pos
+ (save-excursion
+ (goto-char dedenter-pos)
+ (python-indent-line)
+ (unless (= (line-number-at-pos dedenter-pos)
+ (line-number-at-pos current-pos))
+ ;; Reindent region if this is a multiline statement
+ (python-indent-region dedenter-pos current-pos)))))))))
\f
;;; Navigation
: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'
:group 'python
:safe 'listp)
-(defcustom python-shell-virtualenv-path nil
+(defcustom python-shell-virtualenv-root nil
"Path to virtualenv root.
This variable, when set to a string, makes the values stored in
`python-shell-process-environment' and `python-shell-exec-path'
:group 'python
:safe 'stringp)
+(define-obsolete-variable-alias
+ 'python-shell-virtualenv-path 'python-shell-virtualenv-root "25.1")
+
(defcustom python-shell-setup-codes '(python-shell-completion-setup-code
python-ffap-setup-code
python-eldoc-setup-code)
(defun python-shell-get-process-name (dedicated)
"Calculate the appropriate process name for inferior Python process.
-If DEDICATED is t and the variable `buffer-file-name' is non-nil
-returns a string with the form
-`python-shell-buffer-name'[variable `buffer-file-name'] else
-returns the value of `python-shell-buffer-name'."
- (let ((process-name
- (if (and dedicated
- buffer-file-name)
- (format "%s[%s]" python-shell-buffer-name buffer-file-name)
- (format "%s" python-shell-buffer-name))))
- process-name))
+If DEDICATED is t returns a string with the form
+`python-shell-buffer-name'[`buffer-name'] else returns the value
+of `python-shell-buffer-name'."
+ (if dedicated
+ (format "%s[%s]" python-shell-buffer-name (buffer-name))
+ python-shell-buffer-name))
(defun python-shell-internal-get-process-name ()
"Calculate the appropriate process name for Internal Python process.
The name is calculated from `python-shell-global-buffer-name' and
-a hash of all relevant global shell settings in order to ensure
-uniqueness for different types of configurations."
- (format "%s [%s]"
- python-shell-internal-buffer-name
- (md5
- (concat
- python-shell-interpreter
- python-shell-interpreter-args
- python-shell--prompt-calculated-input-regexp
- python-shell--prompt-calculated-output-regexp
- (mapconcat #'symbol-value python-shell-setup-codes "")
- (mapconcat #'identity python-shell-process-environment "")
- (mapconcat #'identity python-shell-extra-pythonpaths "")
- (mapconcat #'identity python-shell-exec-path "")
- (or python-shell-virtualenv-path "")
- (mapconcat #'identity python-shell-exec-path "")))))
-
-(defun python-shell-parse-command () ;FIXME: why name it "parse"?
+the `buffer-name'."
+ (format "%s[%s]" python-shell-internal-buffer-name (buffer-name)))
+
+(defun python-shell-calculate-command ()
"Calculate the string used to execute the inferior Python process."
- ;; FIXME: process-environment doesn't seem to be used anywhere within
- ;; this let.
- (let ((process-environment (python-shell-calculate-process-environment))
- (exec-path (python-shell-calculate-exec-path)))
+ (let ((exec-path (python-shell-calculate-exec-path)))
+ ;; `exec-path' gets tweaked so that virtualenv's specific
+ ;; `python-shell-interpreter' absolute path can be found by
+ ;; `executable-find'.
(format "%s %s"
;; FIXME: Why executable-find?
- (executable-find python-shell-interpreter)
+ (shell-quote-argument
+ (executable-find python-shell-interpreter))
python-shell-interpreter-args)))
-(defun python-new-pythonpath ()
- "Calculate the new PYTHONPATH value from `python-shell-extra-pythonpaths'."
+(define-obsolete-function-alias
+ 'python-shell-parse-command
+ #'python-shell-calculate-command "25.1")
+
+(defun python-shell-calculate-pythonpath ()
+ "Calculate the PYTHONPATH using `python-shell-extra-pythonpaths'."
(let ((pythonpath (getenv "PYTHONPATH"))
(extra (mapconcat 'identity
python-shell-extra-pythonpaths
extra)))
(defun python-shell-calculate-process-environment ()
- "Calculate process environment given `python-shell-virtualenv-path'."
+ "Calculate process environment given `python-shell-virtualenv-root'."
(let ((process-environment (append
python-shell-process-environment
process-environment nil))
- (virtualenv (if python-shell-virtualenv-path
- (directory-file-name python-shell-virtualenv-path)
+ (virtualenv (if python-shell-virtualenv-root
+ (directory-file-name python-shell-virtualenv-root)
nil)))
+ (when python-shell-unbuffered
+ (setenv "PYTHONUNBUFFERED" "1"))
(when python-shell-extra-pythonpaths
- (setenv "PYTHONPATH" (python-new-pythonpath)))
+ (setenv "PYTHONPATH" (python-shell-calculate-pythonpath)))
(if (not virtualenv)
process-environment
(setenv "PYTHONHOME" nil)
process-environment))
(defun python-shell-calculate-exec-path ()
- "Calculate exec path given `python-shell-virtualenv-path'."
- (let ((path (append python-shell-exec-path
- exec-path nil))) ;FIXME: Why nil?
- (if (not python-shell-virtualenv-path)
+ "Calculate exec path given `python-shell-virtualenv-root'."
+ (let ((path (append
+ ;; Use nil as the tail so that the list is a full copy,
+ ;; this is a paranoid safeguard for side-effects.
+ python-shell-exec-path exec-path nil)))
+ (if (not python-shell-virtualenv-root)
path
- (cons (expand-file-name "bin" python-shell-virtualenv-path)
+ (cons (expand-file-name "bin" python-shell-virtualenv-root)
path))))
(defvar python-shell--package-depth 10)
"Execute the forms in BODY with the shell buffer temporarily current.
Signals an error if no shell buffer is available for current buffer."
(declare (indent 0) (debug t))
- (let ((shell-buffer (make-symbol "shell-buffer")))
- `(let ((,shell-buffer (python-shell-get-buffer)))
- (when (not ,shell-buffer)
- (error "No inferior Python buffer available."))
- (with-current-buffer ,shell-buffer
+ (let ((shell-process (make-symbol "shell-process")))
+ `(let ((,shell-process (python-shell-get-process-or-error)))
+ (with-current-buffer (process-buffer ,shell-process)
,@body))))
(defvar python-shell--font-lock-buffer nil)
(when (and python-shell--font-lock-buffer
(buffer-live-p python-shell--font-lock-buffer))
(kill-buffer python-shell--font-lock-buffer)
- (when (eq major-mode 'inferior-python-mode)
+ (when (derived-mode-p 'inferior-python-mode)
(setq python-shell--font-lock-buffer nil)))))
(defmacro python-shell-font-lock-with-font-lock-buffer (&rest body)
(set-buffer python-shell--font-lock-buffer)
(set (make-local-variable 'delay-mode-hooks) t)
(let ((python-indent-guess-indent-offset nil))
- (when (not (eq major-mode 'python-mode))
+ (when (not (derived-mode-p 'python-mode))
(python-mode))
,@body))))
(set (make-local-variable 'python-shell--prompt-calculated-input-regexp) nil)
(set (make-local-variable 'python-shell--prompt-calculated-output-regexp) nil)
(python-shell-prompt-set-calculated-regexps)
- (setq comint-prompt-regexp python-shell--prompt-calculated-input-regexp
- comint-prompt-read-only t)
+ (setq comint-prompt-regexp python-shell--prompt-calculated-input-regexp)
+ (set (make-local-variable 'comint-prompt-read-only) t)
(setq mode-line-process '(":%s"))
(set (make-local-variable 'comint-output-filter-functions)
'(ansi-color-process-output
(python-shell-accept-process-output
(get-buffer-process (current-buffer))))
-(defun python-shell-make-comint (cmd proc-name &optional pop internal)
+(defun python-shell-make-comint (cmd proc-name &optional show internal)
"Create a Python shell comint buffer.
CMD is the Python command to be executed and PROC-NAME is the
process name the comint buffer will get. After the comint buffer
is created the `inferior-python-mode' is activated. When
-optional argument POP is non-nil the buffer is shown. When
+optional argument SHOW is non-nil the buffer is shown. When
optional argument INTERNAL is non-nil this process is run on a
buffer with a name that starts with a space, following the Emacs
convention for temporary/internal buffers, and also makes sure
(mapconcat #'identity args " ")))
(with-current-buffer buffer
(inferior-python-mode))
- (and pop (pop-to-buffer buffer t))
+ (when show (display-buffer buffer))
(and internal (set-process-query-on-exit-flag process nil))))
proc-buffer-name)))
;;;###autoload
-(defun run-python (cmd &optional dedicated show)
+(defun run-python (&optional cmd dedicated show)
"Run an inferior Python process.
-Input and output via buffer named after
-`python-shell-buffer-name'. If there is a process already
-running in that buffer, just switch to it.
-With argument, allows you to define CMD so you can edit the
-command used to call the interpreter and define DEDICATED, so a
-dedicated process for the current buffer is open. When numeric
-prefix arg is other than 0 or 4 do not SHOW.
+Argument CMD defaults to `python-shell-calculate-command' return
+value. When called interactively with `prefix-arg', it allows
+the user to edit such value and choose whether the interpreter
+should be DEDICATED for the current buffer. When numeric prefix
+arg is other than 0 or 4 do not SHOW.
+
+For a given buffer and same values of DEDICATED, if a process is
+already running for it, it will do nothing. This means that if
+the current buffer is using a global process, the user is still
+able to switch it to use a dedicated one.
Runs the hook `inferior-python-mode-hook' after
`comint-mode-hook' is run. (Type \\[describe-mode] in the
(interactive
(if current-prefix-arg
(list
- (read-shell-command "Run Python: " (python-shell-parse-command))
+ (read-shell-command "Run Python: " (python-shell-calculate-command))
(y-or-n-p "Make dedicated process? ")
(= (prefix-numeric-value current-prefix-arg) 4))
- (list (python-shell-parse-command) nil t)))
- (python-shell-make-comint
- cmd (python-shell-get-process-name dedicated) show)
- dedicated)
+ (list (python-shell-calculate-command) nil t)))
+ (get-buffer-process
+ (python-shell-make-comint
+ (or cmd (python-shell-calculate-command))
+ (python-shell-get-process-name dedicated) show)))
(defun run-python-internal ()
"Run an inferior Internal Python process.
(inferior-python-mode-hook nil))
(get-buffer-process
(python-shell-make-comint
- (python-shell-parse-command)
+ (python-shell-calculate-command)
(python-shell-internal-get-process-name) nil t))))
(defun python-shell-get-buffer ()
"Return inferior Python buffer for current buffer.
If current buffer is in `inferior-python-mode', return it."
- (if (eq major-mode 'inferior-python-mode)
+ (if (derived-mode-p 'inferior-python-mode)
(current-buffer)
(let* ((dedicated-proc-name (python-shell-get-process-name t))
(dedicated-proc-buffer-name (format "*%s*" dedicated-proc-name))
"Return inferior Python process for current buffer."
(get-buffer-process (python-shell-get-buffer)))
+(defun python-shell-get-process-or-error (&optional interactivep)
+ "Return inferior Python process for current buffer or signal error.
+When argument INTERACTIVEP is non-nil, use `user-error' instead
+of `error' with a user-friendly message."
+ (or (python-shell-get-process)
+ (if interactivep
+ (user-error
+ "Start a Python process first with `M-x run-python' or `%s'."
+ ;; Get the binding.
+ (key-description
+ (where-is-internal
+ #'run-python overriding-local-map t)))
+ (error
+ "No inferior Python process running."))))
+
(defun python-shell-get-or-create-process (&optional cmd dedicated show)
"Get or create an inferior Python process for current buffer and return it.
Arguments CMD, DEDICATED and SHOW are those of `run-python' and
(run-python cmd dedicated show)))
(or shell-process (python-shell-get-process))))
+(make-obsolete
+ #'python-shell-get-or-create-process
+ "Instead call `python-shell-get-process' and create one if returns nil."
+ "25.1")
+
(defvar python-shell-internal-buffer nil
"Current internal shell buffer for the current buffer.
This is really not necessary at all for the code to work but it's
(defun python-shell-internal-get-or-create-process ()
"Get or create an inferior Internal Python process."
- (let* ((proc-name (python-shell-internal-get-process-name))
- (proc-buffer-name (format " *%s*" proc-name)))
- (when (not (process-live-p proc-name))
- (run-python-internal)
- (setq python-shell-internal-buffer proc-buffer-name))
- (get-buffer-process proc-buffer-name)))
+ (let ((proc-name (python-shell-internal-get-process-name)))
+ (if (process-live-p proc-name)
+ (get-process proc-name)
+ (run-python-internal))))
(define-obsolete-function-alias
'python-proc 'python-shell-internal-get-or-create-process "24.3")
(concat (file-remote-p default-directory) "/tmp")
temporary-file-directory))
(temp-file-name (make-temp-file "py"))
- (coding-system-for-write 'utf-8))
+ (coding-system-for-write (python-info-encoding)))
(with-temp-file temp-file-name
- (insert "# -*- coding: utf-8 -*-\n") ;Not needed for Python-3.
(insert string)
(delete-trailing-whitespace))
temp-file-name))
-(defun python-shell-send-string (string &optional process)
- "Send STRING to inferior Python PROCESS."
- (interactive "sPython command: ")
- (let ((process (or process (python-shell-get-or-create-process))))
+(defun python-shell-send-string (string &optional process msg)
+ "Send STRING to inferior Python PROCESS.
+When optional argument MSG is non-nil, forces display of a
+user-friendly message if there's no process running; defaults to
+t when called interactively."
+ (interactive
+ (list (read-string "Python command: ") nil t))
+ (let ((process (or process (python-shell-get-process-or-error msg))))
(if (string-match ".\n+." string) ;Multiline.
- (let* ((temp-file-name (python-shell--save-temp-file string)))
- (python-shell-send-file temp-file-name process temp-file-name t))
+ (let* ((temp-file-name (python-shell--save-temp-file string))
+ (file-name (or (buffer-file-name) temp-file-name)))
+ (python-shell-send-file file-name process temp-file-name t))
(comint-send-string process string)
(when (or (not (string-match "\n\\'" string))
(string-match "\n[ \t].*\n?\\'" string))
(defun python-shell-send-string-no-output (string &optional process)
"Send STRING to PROCESS and inhibit output.
Return the output."
- (let ((process (or process (python-shell-get-or-create-process)))
+ (let ((process (or process (python-shell-get-process-or-error)))
(comint-preoutput-filter-functions
'(python-shell-output-filter))
(python-shell-output-filter-in-progress t)
(define-obsolete-function-alias
'python-send-string 'python-shell-internal-send-string "24.3")
-(defvar python--use-fake-loc nil
- "If non-nil, use `compilation-fake-loc' to trace errors back to the buffer.
-If nil, regions of text are prepended by the corresponding number of empty
-lines and Python is told to output error messages referring to the whole
-source file.")
-
(defun python-shell-buffer-substring (start end &optional nomain)
"Send buffer substring from START to END formatted for shell.
This is a wrapper over `buffer-substring' that takes care of
\"if __name__ == '__main__'\" block will be removed.
2. When a subregion of the buffer is sent, it takes care of
appending extra empty lines so tracebacks are correct.
- 3. Wraps indented regions under an \"if True:\" block so the
+ 3. When the region sent is a substring of the current buffer, a
+ coding cookie is added.
+ 4. Wraps indented regions under an \"if True:\" block so the
interpreter evaluates them correctly."
- (let ((substring (buffer-substring-no-properties start end))
- (fillstr (unless python--use-fake-loc
- (make-string (1- (line-number-at-pos start)) ?\n)))
- (toplevel-block-p (save-excursion
- (goto-char start)
- (or (zerop (line-number-at-pos start))
- (progn
- (python-util-forward-comment 1)
- (zerop (current-indentation)))))))
+ (let* ((substring (buffer-substring-no-properties start end))
+ (starts-at-point-min-p (save-restriction
+ (widen)
+ (= (point-min) start)))
+ (encoding (python-info-encoding))
+ (fillstr (when (not starts-at-point-min-p)
+ (concat
+ (format "# -*- coding: %s -*-\n" encoding)
+ (make-string
+ ;; Subtract 2 because of the coding cookie.
+ (- (line-number-at-pos start) 2) ?\n))))
+ (toplevel-block-p (save-excursion
+ (goto-char start)
+ (or (zerop (line-number-at-pos start))
+ (progn
+ (python-util-forward-comment 1)
+ (zerop (current-indentation)))))))
(with-temp-buffer
(python-mode)
(if fillstr (insert fillstr))
(insert substring)
(goto-char (point-min))
- (unless python--use-fake-loc
- ;; python-shell--save-temp-file adds an extra coding line, which would
- ;; throw off the line-counts, so let's try to compensate here.
- (if (looking-at "[ \t]*[#\n]")
- (delete-region (point) (line-beginning-position 2))))
(when (not toplevel-block-p)
(insert "if True:")
(delete-region (point) (line-end-position)))
(when (python-nav-if-name-main)
(cons (point)
(progn (python-nav-forward-sexp-safe)
+ ;; Include ending newline
+ (forward-line 1)
(point)))))))
;; Oh destructuring bind, how I miss you.
(if-name-main-start (car if-name-main-start-end))
- (if-name-main-end (cdr if-name-main-start-end)))
+ (if-name-main-end (cdr if-name-main-start-end))
+ (fillstr (make-string
+ (- (line-number-at-pos if-name-main-end)
+ (line-number-at-pos if-name-main-start)) ?\n)))
(when if-name-main-start-end
(goto-char if-name-main-start)
(delete-region if-name-main-start if-name-main-end)
- (insert
- (make-string
- (- (line-number-at-pos if-name-main-end)
- (line-number-at-pos if-name-main-start)) ?\n)))))
+ (insert fillstr))))
+ ;; Ensure there's only one coding cookie in the generated string.
+ (goto-char (point-min))
+ (when (looking-at-p (python-rx coding-cookie))
+ (forward-line 1)
+ (when (looking-at-p (python-rx coding-cookie))
+ (delete-region
+ (line-beginning-position) (line-end-position))))
(buffer-substring-no-properties (point-min) (point-max)))))
-(declare-function compilation-fake-loc "compile"
- (marker file &optional line col))
-
-(defun python-shell-send-region (start end &optional nomain)
- "Send the region delimited by START and END to inferior Python process."
- (interactive "r")
- (let* ((python--use-fake-loc
- (or python--use-fake-loc (not buffer-file-name)))
- (string (python-shell-buffer-substring start end nomain))
- (process (python-shell-get-or-create-process))
- (_ (string-match "\\`\n*\\(.*\\)" string)))
- (message "Sent: %s..." (match-string 1 string))
- (let* ((temp-file-name (python-shell--save-temp-file string))
- (file-name (or (buffer-file-name) temp-file-name)))
- (python-shell-send-file file-name process temp-file-name t)
- (unless python--use-fake-loc
- (with-current-buffer (process-buffer process)
- (compilation-fake-loc (copy-marker start) temp-file-name
- 2)) ;; Not 1, because of the added coding line.
- ))))
-
-(defun python-shell-send-buffer (&optional arg)
+(defun python-shell-send-region (start end &optional send-main msg)
+ "Send the region delimited by START and END to inferior Python process.
+When optional argument SEND-MAIN is non-nil, allow execution of
+code inside blocks delimited by \"if __name__== '__main__':\".
+When called interactively SEND-MAIN defaults to nil, unless it's
+called with prefix argument. When optional argument MSG is
+non-nil, forces display of a user-friendly message if there's no
+process running; defaults to t when called interactively."
+ (interactive
+ (list (region-beginning) (region-end) current-prefix-arg t))
+ (let* ((string (python-shell-buffer-substring start end (not send-main)))
+ (process (python-shell-get-process-or-error msg))
+ (original-string (buffer-substring-no-properties start end))
+ (_ (string-match "\\`\n*\\(.*\\)" original-string)))
+ (message "Sent: %s..." (match-string 1 original-string))
+ (python-shell-send-string string process)))
+
+(defun python-shell-send-buffer (&optional send-main msg)
"Send the entire buffer to inferior Python process.
-With prefix ARG allow execution of code inside blocks delimited
-by \"if __name__== '__main__':\"."
- (interactive "P")
+When optional argument SEND-MAIN is non-nil, allow execution of
+code inside blocks delimited by \"if __name__== '__main__':\".
+When called interactively SEND-MAIN defaults to nil, unless it's
+called with prefix argument. When optional argument MSG is
+non-nil, forces display of a user-friendly message if there's no
+process running; defaults to t when called interactively."
+ (interactive (list current-prefix-arg t))
(save-restriction
(widen)
- (python-shell-send-region (point-min) (point-max) (not arg))))
+ (python-shell-send-region (point-min) (point-max) send-main msg)))
-(defun python-shell-send-defun (arg)
+(defun python-shell-send-defun (&optional arg msg)
"Send the current defun to inferior Python process.
-When argument ARG is non-nil do not include decorators."
- (interactive "P")
+When argument ARG is non-nil do not include decorators. When
+optional argument MSG is non-nil, forces display of a
+user-friendly message if there's no process running; defaults to
+t when called interactively."
+ (interactive (list current-prefix-arg t))
(save-excursion
(python-shell-send-region
(progn
(progn
(or (python-nav-end-of-defun)
(end-of-line 1))
- (point-marker)))))
+ (point-marker))
+ nil ;; noop
+ msg)))
(defun python-shell-send-file (file-name &optional process temp-file-name
- delete)
+ delete msg)
"Send FILE-NAME to inferior Python PROCESS.
If TEMP-FILE-NAME is passed then that file is used for processing
-instead, while internally the shell will continue to use FILE-NAME.
-If DELETE is non-nil, delete the file afterwards."
- (interactive "fFile to send: ")
- (let* ((process (or process (python-shell-get-or-create-process)))
+instead, while internally the shell will continue to use
+FILE-NAME. If TEMP-FILE-NAME and DELETE are non-nil, then
+TEMP-FILE-NAME is deleted after evaluation is performed. When
+optional argument MSG is non-nil, forces display of a
+user-friendly message if there's no process running; defaults to
+t when called interactively."
+ (interactive
+ (list
+ (read-file-name "File to send: ") ; file-name
+ nil ; process
+ nil ; temp-file-name
+ nil ; delete
+ t)) ; msg
+ (let* ((process (or process (python-shell-get-process-or-error msg)))
+ (encoding (with-temp-buffer
+ (insert-file-contents
+ (or temp-file-name file-name))
+ (python-info-encoding)))
+ (file-name (expand-file-name
+ (or (file-remote-p file-name 'localname)
+ file-name)))
(temp-file-name (when temp-file-name
(expand-file-name
(or (file-remote-p temp-file-name 'localname)
- temp-file-name))))
- (file-name (or (when file-name
- (expand-file-name
- (or (file-remote-p file-name 'localname)
- file-name)))
- temp-file-name)))
- (when (not file-name)
- (error "If FILE-NAME is nil then TEMP-FILE-NAME must be non-nil"))
+ temp-file-name)))))
(python-shell-send-string
(format
- (concat "__pyfile = open('''%s''');"
- "exec(compile(__pyfile.read(), '''%s''', 'exec'));"
- "__pyfile.close()%s")
- (or temp-file-name file-name) file-name
- (if delete (format "; import os; os.remove('''%s''')"
- (or temp-file-name file-name))
- ""))
+ (concat
+ "import codecs, os;"
+ "__pyfile = codecs.open('''%s''', encoding='''%s''');"
+ "__code = __pyfile.read().encode('''%s''');"
+ "__pyfile.close();"
+ (when (and delete temp-file-name)
+ (format "os.remove('''%s''');" temp-file-name))
+ "exec(compile(__code, '''%s''', 'exec'));")
+ (or temp-file-name file-name) encoding encoding file-name)
process)))
-(defun python-shell-switch-to-shell ()
- "Switch to inferior Python process buffer."
- (interactive)
- (process-buffer (python-shell-get-or-create-process)) t)
+(defun python-shell-switch-to-shell (&optional msg)
+ "Switch to inferior Python process buffer.
+When optional argument MSG is non-nil, forces display of a
+user-friendly message if there's no process running; defaults to
+t when called interactively."
+ (interactive "p")
+ (pop-to-buffer
+ (process-buffer (python-shell-get-process-or-error msg)) nil t))
(defun python-shell-send-setup-code ()
"Send all setup code for shell.
(defcustom python-shell-completion-setup-code
"try:
- import readline, rlcompleter
+ import __builtin__
except ImportError:
+ # Python 3
+ import builtins as __builtin__
+try:
+ import readline, rlcompleter
+except:
def __PYTHON_EL_get_completions(text):
return []
else:
def __PYTHON_EL_get_completions(text):
+ builtins = dir(__builtin__)
completions = []
try:
splits = text.split()
is_module = splits and splits[0] in ('from', 'import')
- is_ipython = getattr(
- __builtins__, '__IPYTHON__',
- getattr(__builtins__, '__IPYTHON__active', False))
+ is_ipython = ('__IPYTHON__' in builtins or
+ '__IPYTHON__active' in builtins)
if is_module:
from IPython.core.completerlib import module_completion
completions = module_completion(text.strip())
- elif is_ipython and getattr(__builtins__, '__IP', None):
+ elif is_ipython and '__IP' in builtins:
completions = __IP.complete(text)
- elif is_ipython and getattr(__builtins__, 'get_ipython', None):
+ elif is_ipython and 'get_ipython' in builtins:
completions = get_ipython().Completer.all_completions(text)
else:
i = 0
"25.1"
"Completion string code must work for (i)pdb.")
+(defcustom python-shell-completion-native-disabled-interpreters
+ ;; PyPy's readline cannot handle some escape sequences yet.
+ (list "pypy")
+ "List of disabled interpreters.
+When a match is found, native completion is disabled."
+ :type '(repeat string))
+
+(defcustom python-shell-completion-native-enable t
+ "Enable readline based native completion."
+ :type 'boolean)
+
+(defcustom python-shell-completion-native-output-timeout 0.01
+ "Time in seconds to wait for completion output before giving up."
+ :type 'float)
+
+(defvar python-shell-completion-native-redirect-buffer
+ " *Python completions redirect*"
+ "Buffer to be used to redirect output of readline commands.")
+
+(defun python-shell-completion-native-interpreter-disabled-p ()
+ "Return non-nil if interpreter has native completion disabled."
+ (when python-shell-completion-native-disabled-interpreters
+ (string-match
+ (regexp-opt python-shell-completion-native-disabled-interpreters)
+ (file-name-nondirectory python-shell-interpreter))))
+
+(defun python-shell-completion-native-try ()
+ "Return non-nil if can trigger native completion."
+ (let ((python-shell-completion-native-enable t))
+ (python-shell-completion-native-get-completions
+ (get-buffer-process (current-buffer))
+ nil "int")))
+
+(defun python-shell-completion-native-setup ()
+ "Try to setup native completion, return non-nil on success."
+ (let ((process (python-shell-get-process)))
+ (python-shell-send-string
+ (funcall
+ 'mapconcat
+ #'identity
+ (list
+ "try:"
+ " import readline, rlcompleter"
+ ;; Remove parens on callables as it breaks completion on
+ ;; arguments (e.g. str(Ari<tab>)).
+ " class Completer(rlcompleter.Completer):"
+ " def _callable_postfix(self, val, word):"
+ " return word"
+ " readline.set_completer(Completer().complete)"
+ " if readline.__doc__ and 'libedit' in readline.__doc__:"
+ " readline.parse_and_bind('bind ^I rl_complete')"
+ " else:"
+ " readline.parse_and_bind('tab: complete')"
+ " print ('python.el: readline is available')"
+ "except:"
+ " print ('python.el: readline not available')")
+ "\n")
+ process)
+ (python-shell-accept-process-output process)
+ (when (save-excursion
+ (re-search-backward
+ (regexp-quote "python.el: readline is available") nil t 1))
+ (python-shell-completion-native-try))))
+
+(defun python-shell-completion-native-turn-off (&optional msg)
+ "Turn off shell native completions.
+With argument MSG show deactivation message."
+ (interactive "p")
+ (python-shell-with-shell-buffer
+ (set (make-local-variable 'python-shell-completion-native-enable) nil)
+ (when msg
+ (message "Shell native completion is disabled, using fallback"))))
+
+(defun python-shell-completion-native-turn-on (&optional msg)
+ "Turn on shell native completions.
+With argument MSG show deactivation message."
+ (interactive "p")
+ (python-shell-with-shell-buffer
+ (set (make-local-variable 'python-shell-completion-native-enable) t)
+ (python-shell-completion-native-turn-on-maybe msg)))
+
+(defun python-shell-completion-native-turn-on-maybe (&optional msg)
+ "Turn on native completions if enabled and available.
+With argument MSG show activation/deactivation message."
+ (interactive "p")
+ (python-shell-with-shell-buffer
+ (when python-shell-completion-native-enable
+ (cond
+ ((python-shell-completion-native-interpreter-disabled-p)
+ (python-shell-completion-native-turn-off msg))
+ ((python-shell-completion-native-setup)
+ (when msg
+ (message "Shell native completion is enabled.")))
+ (t (lwarn
+ '(python python-shell-completion-native-turn-on-maybe)
+ :warning
+ (concat
+ "Your `python-shell-interpreter' doesn't seem to "
+ "support readline, yet `python-shell-completion-native' "
+ (format "was `t' and %S is not part of the "
+ (file-name-nondirectory python-shell-interpreter))
+ "`python-shell-completion-native-disabled-interpreters' "
+ "list. Native completions have been disabled locally. "))
+ (python-shell-completion-native-turn-off msg))))))
+
+(defun python-shell-completion-native-turn-on-maybe-with-msg ()
+ "Like `python-shell-completion-native-turn-on-maybe' but force messages."
+ (python-shell-completion-native-turn-on-maybe t))
+
+(add-hook 'inferior-python-mode-hook
+ #'python-shell-completion-native-turn-on-maybe-with-msg)
+
+(defun python-shell-completion-native-toggle (&optional msg)
+ "Toggle shell native completion.
+With argument MSG show activation/deactivation message."
+ (interactive "p")
+ (python-shell-with-shell-buffer
+ (if python-shell-completion-native-enable
+ (python-shell-completion-native-turn-off msg)
+ (python-shell-completion-native-turn-on msg))
+ python-shell-completion-native-enable))
+
+(defun python-shell-completion-native-get-completions (process import input)
+ "Get completions using native readline for PROCESS.
+When IMPORT is non-nil takes precedence over INPUT for
+completion."
+ (when (and python-shell-completion-native-enable
+ (python-util-comint-last-prompt)
+ (>= (point) (cdr (python-util-comint-last-prompt))))
+ (let* ((input (or import input))
+ (original-filter-fn (process-filter process))
+ (redirect-buffer (get-buffer-create
+ python-shell-completion-native-redirect-buffer))
+ (separators (python-rx
+ (or whitespace open-paren close-paren)))
+ (trigger "\t\t\t")
+ (new-input (concat input trigger))
+ (input-length
+ (save-excursion
+ (+ (- (point-max) (comint-bol)) (length new-input))))
+ (delete-line-command (make-string input-length ?\b))
+ (input-to-send (concat new-input delete-line-command)))
+ ;; Ensure restoring the process filter, even if the user quits
+ ;; or there's some other error.
+ (unwind-protect
+ (with-current-buffer redirect-buffer
+ ;; Cleanup the redirect buffer
+ (delete-region (point-min) (point-max))
+ ;; Mimic `comint-redirect-send-command', unfortunately it
+ ;; can't be used here because it expects a newline in the
+ ;; command and that's exactly what we are trying to avoid.
+ (let ((comint-redirect-echo-input nil)
+ (comint-redirect-verbose nil)
+ (comint-redirect-perform-sanity-check nil)
+ (comint-redirect-insert-matching-regexp nil)
+ ;; Feed it some regex that will never match.
+ (comint-redirect-finished-regexp "^\\'$")
+ (comint-redirect-output-buffer redirect-buffer))
+ ;; Compatibility with Emacs 24.x. Comint changed and
+ ;; now `comint-redirect-filter' gets 3 args. This
+ ;; checks which version of `comint-redirect-filter' is
+ ;; in use based on its args and uses `apply-partially'
+ ;; to make it up for the 3 args case.
+ (if (= (length
+ (help-function-arglist 'comint-redirect-filter)) 3)
+ (set-process-filter
+ process (apply-partially
+ #'comint-redirect-filter original-filter-fn))
+ (set-process-filter process #'comint-redirect-filter))
+ (process-send-string process input-to-send)
+ (accept-process-output
+ process
+ python-shell-completion-native-output-timeout)
+ ;; XXX: can't use `python-shell-accept-process-output'
+ ;; here because there are no guarantees on how output
+ ;; ends. The workaround here is to call
+ ;; `accept-process-output' until we don't find anything
+ ;; else to accept.
+ (while (accept-process-output
+ process
+ python-shell-completion-native-output-timeout))
+ (cl-remove-duplicates
+ (split-string
+ (buffer-substring-no-properties
+ (point-min) (point-max))
+ separators t))))
+ (set-process-filter process original-filter-fn)))))
+
(defun python-shell-completion-get-completions (process import input)
"Do completion at point using PROCESS for IMPORT or INPUT.
When IMPORT is non-nil takes precedence over INPUT for
completion."
(with-current-buffer (process-buffer process)
(let* ((prompt
- ;; Get last prompt of the inferior process buffer (this
- ;; intentionally avoids using `comint-last-prompt' because
- ;; of incompatibilities with Emacs 24.x).
- (save-excursion
+ (let ((prompt-boundaries (python-util-comint-last-prompt)))
(buffer-substring-no-properties
- (line-beginning-position) ;End of prompt.
- (re-search-backward "^"))))
+ (car prompt-boundaries) (cdr prompt-boundaries))))
(completion-code
;; Check whether a prompt matches a pdb string, an import
;; statement or just the standard prompt and use the
last-prompt-end
(forward-char (length (match-string-no-properties 0)))
(point))))
- (end (point)))
+ (end (point))
+ (completion-fn
+ (if python-shell-completion-native-enable
+ #'python-shell-completion-native-get-completions
+ #'python-shell-completion-get-completions)))
(list start end
(completion-table-dynamic
(apply-partially
- #'python-shell-completion-get-completions
+ completion-fn
process import-statement)))))
(define-obsolete-function-alias
(defun python-ffap-module-path (module)
"Function for `ffap-alist' to return path for MODULE."
(let ((process (or
- (and (eq major-mode 'inferior-python-mode)
+ (and (derived-mode-p 'inferior-python-mode)
(get-buffer-process (current-buffer)))
(python-shell-get-process))))
(if (not process)
"def __PYDOC_get_help(obj):
try:
import inspect
- if hasattr(obj, 'startswith'):
+ try:
+ str_type = basestring
+ except NameError:
+ str_type = str
+ if isinstance(obj, str_type):
obj = eval(obj, globals())
doc = inspect.getdoc(obj)
if not doc and callable(obj):
doc = doc.splitlines()[0]
except:
doc = ''
- try:
- exec('print doc')
- except SyntaxError:
- print(doc)"
+ print (doc)"
"Python code to setup documentation retrieval."
:type 'string
:group 'python)
(let ((input (or force-input
(python-info-current-symbol t))))
(and input
- (python-shell-send-string-no-output
- (format python-eldoc-string-code input)
- process))))))
+ ;; Prevent resizing the echo area when iPython is
+ ;; enabled. Bug#18794.
+ (python-util-strip-string
+ (python-shell-send-string-no-output
+ (format python-eldoc-string-code input)
+ process)))))))
(defun python-eldoc-function ()
"`eldoc-documentation-function' for Python.
(* whitespace) line-end))
(string-equal "" (match-string-no-properties 1))))
+(defun python-info-encoding-from-cookie ()
+ "Detect current buffer's encoding from its coding cookie.
+Returns the encoding as a symbol."
+ (let ((first-two-lines
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-line 2)
+ (buffer-substring-no-properties
+ (point)
+ (point-min))))))
+ (when (string-match (python-rx coding-cookie) first-two-lines)
+ (intern (match-string-no-properties 1 first-two-lines)))))
+
+(defun python-info-encoding ()
+ "Return encoding for file.
+Try `python-info-encoding-from-cookie', if none is found then
+default to utf-8."
+ ;; If no encoding is defined, then it's safe to use UTF-8: Python 2
+ ;; uses ASCII as default while Python 3 uses UTF-8. This means that
+ ;; in the worst case scenario python.el will make things work for
+ ;; Python 2 files with unicode data and no encoding defined.
+ (or (python-info-encoding-from-cookie)
+ 'utf-8))
+
\f
;;; Utility functions
'python-nav-forward-sexp)
(set (make-local-variable 'font-lock-defaults)
- '(python-font-lock-keywords nil nil nil nil))
+ '(python-font-lock-keywords
+ nil nil nil nil
+ (font-lock-syntactic-face-function
+ . python-font-lock-syntactic-face-function)))
(set (make-local-variable 'syntax-propertize-function)
python-syntax-propertize-function)
#'python-indent-line-function)
(set (make-local-variable 'indent-region-function) #'python-indent-region)
;; Because indentation is not redundant, we cannot safely reindent code.
- (setq-local electric-indent-inhibit t)
- (setq-local electric-indent-chars (cons ?: electric-indent-chars))
+ (set (make-local-variable 'electric-indent-inhibit) t)
+ (set (make-local-variable 'electric-indent-chars)
+ (cons ?: electric-indent-chars))
;; Add """ ... """ pairing to electric-pair-mode.
(add-hook 'post-self-insert-hook