;;; python.el --- Python's flying circus support for Emacs -*- lexical-binding: t -*-
-;; Copyright (C) 2003-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2003-2016 Free Software Foundation, Inc.
;; Author: Fabián E. Gallina <fgallina@gnu.org>
;; URL: https://github.com/fgallina/python.el
-;; Version: 0.25.1
+;; Version: 0.25.2
;; Package-Requires: ((emacs "24.1") (cl-lib "1.0"))
;; Maintainer: emacs-devel@gnu.org
;; Created: Jul 2010
(autoload 'help-function-arglist "help-fns")
;;;###autoload
-(add-to-list 'auto-mode-alist (cons (purecopy "\\.py\\'") 'python-mode))
+(add-to-list 'auto-mode-alist (cons (purecopy "\\.pyw?\\'") 'python-mode))
;;;###autoload
(add-to-list 'interpreter-mode-alist (cons (purecopy "python[0-9.]*") 'python-mode))
;; Some util commands
(define-key map "\C-c\C-v" 'python-check)
(define-key map "\C-c\C-f" 'python-eldoc-at-point)
+ (define-key map "\C-c\C-d" 'python-describe-at-point)
;; Utilities
(substitute-key-definition 'complete-symbol 'completion-at-point
map global-map)
(defconst python-rx-constituents
`((block-start . ,(rx symbol-start
(or "def" "class" "if" "elif" "else" "try"
- "except" "finally" "for" "while" "with")
+ "except" "finally" "for" "while" "with"
+ ;; Python 3.5+ PEP492
+ (and "async" (+ space)
+ (or "def" "for" "with")))
symbol-end))
(dedenter . ,(rx symbol-start
(or "elif" "else" "except" "finally")
symbol-end))
(decorator . ,(rx line-start (* space) ?@ (any letter ?_)
(* (any word ?_))))
- (defun . ,(rx symbol-start (or "def" "class") symbol-end))
+ (defun . ,(rx symbol-start
+ (or "def" "class"
+ ;; Python 3.5+ PEP492
+ (and "async" (+ space) "def"))
+ symbol-end))
(if-name-main . ,(rx line-start "if" (+ space) "__name__"
(+ space) "==" (+ space)
(any ?' ?\") "__main__" (any ?' ?\")
((nth 1 ppss) 'paren))))
(defsubst python-syntax-comment-or-string-p (&optional ppss)
- "Return non-nil if PPSS is inside 'comment or 'string."
+ "Return non-nil if PPSS is inside comment or string."
(nth 8 (or ppss (syntax-ppss))))
(defsubst python-syntax-closing-paren-p ()
"Return non-nil if char after point is a closing paren."
- (= (syntax-class (syntax-after (point)))
- (syntax-class (string-to-syntax ")"))))
+ (eql (syntax-class (syntax-after (point)))
+ (syntax-class (string-to-syntax ")"))))
(define-obsolete-function-alias
'python-info-ppss-context #'python-syntax-context "24.3")
;; fontified like that in order to keep font-lock consistent between
;; Python versions.
"nonlocal"
+ ;; Python 3.5+ PEP492
+ (and "async" (+ space) (or "def" "for" "with"))
+ "await"
;; Extra:
"self")
symbol-end)
;; Builtin Exceptions
(,(rx symbol-start
(or
+ ;; Python 2 and 3:
"ArithmeticError" "AssertionError" "AttributeError" "BaseException"
- "DeprecationWarning" "EOFError" "EnvironmentError" "Exception"
- "FloatingPointError" "FutureWarning" "GeneratorExit" "IOError"
- "ImportError" "ImportWarning" "IndexError" "KeyError"
- "KeyboardInterrupt" "LookupError" "MemoryError" "NameError"
- "NotImplementedError" "OSError" "OverflowError"
- "PendingDeprecationWarning" "ReferenceError" "RuntimeError"
- "RuntimeWarning" "StopIteration" "SyntaxError" "SyntaxWarning"
- "SystemError" "SystemExit" "TypeError" "UnboundLocalError"
- "UnicodeDecodeError" "UnicodeEncodeError" "UnicodeError"
- "UnicodeTranslateError" "UnicodeWarning" "UserWarning" "VMSError"
- "ValueError" "Warning" "WindowsError" "ZeroDivisionError"
+ "BufferError" "BytesWarning" "DeprecationWarning" "EOFError"
+ "EnvironmentError" "Exception" "FloatingPointError" "FutureWarning"
+ "GeneratorExit" "IOError" "ImportError" "ImportWarning"
+ "IndentationError" "IndexError" "KeyError" "KeyboardInterrupt"
+ "LookupError" "MemoryError" "NameError" "NotImplementedError"
+ "OSError" "OverflowError" "PendingDeprecationWarning"
+ "ReferenceError" "RuntimeError" "RuntimeWarning" "StopIteration"
+ "SyntaxError" "SyntaxWarning" "SystemError" "SystemExit" "TabError"
+ "TypeError" "UnboundLocalError" "UnicodeDecodeError"
+ "UnicodeEncodeError" "UnicodeError" "UnicodeTranslateError"
+ "UnicodeWarning" "UserWarning" "ValueError" "Warning"
+ "ZeroDivisionError"
;; Python 2:
"StandardError"
;; Python 3:
- "BufferError" "BytesWarning" "IndentationError" "ResourceWarning"
- "TabError")
+ "BlockingIOError" "BrokenPipeError" "ChildProcessError"
+ "ConnectionAbortedError" "ConnectionError" "ConnectionRefusedError"
+ "ConnectionResetError" "FileExistsError" "FileNotFoundError"
+ "InterruptedError" "IsADirectoryError" "NotADirectoryError"
+ "PermissionError" "ProcessLookupError" "RecursionError"
+ "ResourceWarning" "StopAsyncIteration" "TimeoutError"
+ ;; OS specific
+ "VMSError" "WindowsError"
+ )
symbol-end) . font-lock-type-face)
;; Builtins
(,(rx symbol-start
((python-rx string-delimiter)
(0 (ignore (python-syntax-stringify))))))
+(defconst python--prettify-symbols-alist
+ '(("lambda" . ?λ)
+ ("and" . ?∧)
+ ("or" . ?∨)))
+
(defsubst python-syntax-count-quotes (quote-char &optional point limit)
"Count number of quotes around point (max is 3).
QUOTE-CHAR is the quote char to count. Optional argument POINT is
(defcustom python-indent-guess-indent-offset-verbose t
"Non-nil means to emit a warning when indentation guessing fails."
+ :version "25.1"
:type 'boolean
:group 'python
:safe' booleanp)
(defun python-nav-if-name-main ()
"Move point at the beginning the __main__ block.
-When \"if __name__ == '__main__':\" is found returns its
+When \"if __name__ == \\='__main__\\=':\" is found returns its
position, else returns nil."
(interactive)
(let ((point (point))
here. Normally you wont use this variable directly unless you
plan to ensure a particular set of paths to all Python shell
executed through tramp connections."
+ :version "25.1"
:type '(repeat string)
:group 'python)
(defun python-shell-calculate-pythonpath ()
"Calculate the PYTHONPATH using `python-shell-extra-pythonpaths'."
(let ((pythonpath
- (tramp-compat-split-string
- (or (getenv "PYTHONPATH") "") path-separator)))
+ (split-string
+ (or (getenv "PYTHONPATH") "") path-separator 'omit)))
(python-shell--add-to-path-with-priority
pythonpath python-shell-extra-pythonpaths)
(mapconcat 'identity pythonpath path-separator)))
(md5 tramp-end-of-output)))
unset vars item)
(while env
- (setq item (tramp-compat-split-string (car env) "="))
+ (setq item (split-string (car env) "=" 'omit))
(setcdr item (mapconcat 'identity (cdr item) "="))
(if (and (stringp (cdr item)) (not (string-equal (cdr item) "")))
(push (format "%s %s" (car item) (cdr item)) vars)
;; shell, otherwise (like in the case of processes started
;; with `process-file') the environment is not changed.
;; This makes environment modifications effective
- ;; inconditionally.
+ ;; unconditionally.
(python-shell-tramp-refresh-process-environment
,vec tramp-remote-process-environment))
,(macroexp-progn body)))))
interactive actions can be performed. This is useful to safely
attach setup code for long-running processes that eventually
provide a shell."
+ :version "25.1"
:type 'hook
:group 'python)
\(Type \\[describe-mode] in the process buffer for a list of commands.)"
(when python-shell--parent-buffer
(python-util-clone-local-variables python-shell--parent-buffer))
+ (set (make-local-variable 'indent-tabs-mode) nil)
;; Users can interactively override default values for
;; `python-shell-interpreter' and `python-shell-interpreter-args'
;; when calling `run-python'. This ensures values let-bound in
(process (get-buffer-process buffer))
;; Users can override the interpreter and args
;; interactively when calling `run-python', let-binding
- ;; these allows to have the new right values in all
+ ;; these allows having the new right values in all
;; setup code that is done in `inferior-python-mode',
;; which is important, especially for prompt detection.
(python-shell--interpreter interpreter)
(or (python-shell-get-process)
(if interactivep
(user-error
- "Start a Python process first with ‘%s’ or ‘%s’."
+ "Start a Python process first with `%s' or `%s'."
(substitute-command-keys "\\[run-python]")
;; Get the binding.
(key-description
different transformations for the code sent to be evaluated in
the python shell:
1. When optional argument NOMAIN is non-nil everything under an
- \"if __name__ == '__main__'\" block will be removed.
+ \"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. When the region sent is a substring of the current buffer, a
(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__':\".
+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
(defun python-shell-send-buffer (&optional send-main msg)
"Send the entire buffer to inferior Python process.
When optional argument SEND-MAIN is non-nil, allow execution of
-code inside blocks delimited by \"if __name__== '__main__':\".
+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
(list "pypy")
"List of disabled interpreters.
When a match is found, native completion is disabled."
+ :version "25.1"
:type '(repeat string))
(defcustom python-shell-completion-native-enable t
"Enable readline based native completion."
+ :version "25.1"
:type 'boolean)
(defcustom python-shell-completion-native-output-timeout 5.0
"Time in seconds to wait for completion output before giving up."
+ :version "25.1"
:type 'float)
(defcustom python-shell-completion-native-try-output-timeout 1.0
"Time in seconds to wait for *trying* native completion output."
+ :version "25.1"
:type 'float)
(defvar python-shell-completion-native-redirect-buffer
if not completion:
if self.last_completion != '1__dummy_completion__':
# When no more completions are available, returning a
- # dummy with non-sharing prefix allow to ensure output
+ # dummy with non-sharing prefix allow ensuring output
# while preventing changes to current input.
# Coincidentally it's also the end of output.
completion = '1__dummy_completion__'
(forward-char (length (match-string-no-properties 0)))
(point))))
(end (point))
- (prompt-boundaries (python-util-comint-last-prompt))
+ (prompt-boundaries
+ (with-current-buffer (process-buffer process)
+ (python-util-comint-last-prompt)))
(prompt
(with-current-buffer (process-buffer process)
(when prompt-boundaries
"Set the buffer for FILE-NAME as the tracked buffer.
Internally it uses the `python-pdbtrack-tracked-buffer' variable.
Returns the tracked buffer."
- (let ((file-buffer (get-file-buffer
- (concat (file-remote-p default-directory)
- file-name))))
+ (let* ((file-name-prospect (concat (file-remote-p default-directory)
+ file-name))
+ (file-buffer (get-file-buffer file-name-prospect)))
(if file-buffer
(setq python-pdbtrack-tracked-buffer file-buffer)
- (setq file-buffer (find-file-noselect file-name))
+ (cond
+ ((file-exists-p file-name-prospect)
+ (setq file-buffer (find-file-noselect file-name-prospect)))
+ ((and (not (equal file-name file-name-prospect))
+ (file-exists-p file-name))
+ ;; Fallback to a locally available copy of the file.
+ (setq file-buffer (find-file-noselect file-name-prospect))))
(when (not (member file-buffer python-pdbtrack-buffers-to-kill))
(add-to-list 'python-pdbtrack-buffers-to-kill file-buffer)))
file-buffer))
(declare (indent 2))
(let* ((name (symbol-name name))
(function-name (intern (concat "python-skeleton--" name)))
- (msg (format
- "Add '%s' clause? " name)))
+ (msg (funcall (if (fboundp 'format-message) #'format-message #'format)
+ "Add `%s' clause? " name)))
(when (not skel)
(setq skel
`(< ,(format "%s:" name) \n \n
(unless (zerop (length docstring))
docstring)))))
+(defvar-local python-eldoc-get-doc t
+ "Non-nil means eldoc should fetch the documentation
+ automatically. Set to nil by `python-eldoc-function' if
+ `python-eldoc-function-timeout-permanent' is non-nil and
+ `python-eldoc-function' times out.")
+
+(defcustom python-eldoc-function-timeout 1
+ "Timeout for `python-eldoc-function' in seconds."
+ :group 'python
+ :type 'integer
+ :version "25.1")
+
+(defcustom python-eldoc-function-timeout-permanent t
+ "Non-nil means that when `python-eldoc-function' times out
+`python-eldoc-get-doc' will be set to nil"
+ :group 'python
+ :type 'boolean
+ :version "25.1")
+
(defun python-eldoc-function ()
"`eldoc-documentation-function' for Python.
For this to work as best as possible you should call
`python-shell-send-buffer' from time to time so context in
-inferior Python process is updated properly."
- (python-eldoc--get-doc-at-point))
+inferior Python process is updated properly.
+
+If `python-eldoc-function-timeout' seconds elapse before this
+function returns then if
+`python-eldoc-function-timeout-permanent' is non-nil
+`python-eldoc-get-doc' will be set to nil and eldoc will no
+longer return the documentation at the point automatically.
+
+Set `python-eldoc-get-doc' to t to reenable eldoc documentation
+fetching"
+ (when python-eldoc-get-doc
+ (with-timeout (python-eldoc-function-timeout
+ (if python-eldoc-function-timeout-permanent
+ (progn
+ (message "Eldoc echo-area display muted in this buffer, see `python-eldoc-function'")
+ (setq python-eldoc-get-doc nil))
+ (message "`python-eldoc-function' timed out, see `python-eldoc-function-timeout'")))
+ (python-eldoc--get-doc-at-point))))
(defun python-eldoc-at-point (symbol)
"Get help on SYMBOL using `help'.
nil nil symbol))))
(message (python-eldoc--get-doc-at-point symbol)))
+(defun python-describe-at-point (symbol process)
+ (interactive (list (python-info-current-symbol)
+ (python-shell-get-process)))
+ (comint-send-string process (concat "help('" symbol "')\n")))
+
\f
;;; Hideshow
(current-column))))
(^ '(- (1+ (current-indentation))))))
- (if (null eldoc-documentation-function)
- ;; Emacs<25
- (set (make-local-variable 'eldoc-documentation-function)
- #'python-eldoc-function)
- (add-function :before-until (local 'eldoc-documentation-function)
- #'python-eldoc-function))
+ (if (boundp 'eldoc-documentation-functions)
+ (add-hook 'eldoc-documentation-functions #'python-eldoc-function nil t)
+ (if (null eldoc-documentation-function)
+ ;; Emacs<25
+ (set (make-local-variable 'eldoc-documentation-function)
+ #'python-eldoc-function)
+ (add-function :before-until (local 'eldoc-documentation-function)
+ #'python-eldoc-function)))
(add-to-list
'hs-special-modes-alist
"`outline-level' function for Python mode."
(1+ (/ (current-indentation) python-indent-offset))))
+ (set (make-local-variable 'prettify-symbols-alist)
+ python--prettify-symbols-alist)
+
(python-skeleton-add-menu-items)
(make-local-variable 'python-shell-internal-buffer)
(provide 'python)
;; Local Variables:
-;; coding: utf-8
;; indent-tabs-mode: nil
;; End: