Mercurial > hg > dotemacs
diff elpa/elpy-1.14.1/elpy.el @ 156:c745e2cc79ee
elpy: update along with direct deps
author | Jordi GutiƩrrez Hermoso <jordigh@octave.org> |
---|---|
date | Mon, 27 Feb 2017 12:17:38 -0500 (2017-02-27) |
parents | elpa/elpy-1.12.0/elpy.el@55ceabc58fcc |
children |
line wrap: on
line diff
copy from elpa/elpy-1.12.0/elpy.el copy to elpa/elpy-1.14.1/elpy.el --- a/elpa/elpy-1.12.0/elpy.el +++ b/elpa/elpy-1.14.1/elpy.el @@ -4,9 +4,9 @@ ;; Author: Jorgen Schaefer <contact@jorgenschaefer.de> ;; URL: https://github.com/jorgenschaefer/elpy -;; Version: 1.12.0 +;; Version: 1.14.1 ;; Keywords: Python, IDE, Languages, Tools -;; Package-Requires: ((company "0.8.2") (find-file-in-project "3.3") (highlight-indentation "0.5.0") (pyvenv "1.3") (yasnippet "0.8.0")) +;; Package-Requires: ((company "0.8.2") (find-file-in-project "3.3") (highlight-indentation "0.5.0") (pyvenv "1.3") (yasnippet "0.8.0") (s "1.10.0")) ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License @@ -44,9 +44,10 @@ (require 'python) (require 'elpy-refactor) +(require 'elpy-django) (require 'pyvenv) -(defconst elpy-version "1.12.0" +(defconst elpy-version "1.14.1" "The version of the Elpy lisp code.") ;;;;;;;;;;;;;;;;;;;;;; @@ -71,7 +72,8 @@ elpy-module-flymake elpy-module-highlight-indentation elpy-module-pyvenv - elpy-module-yasnippet) + elpy-module-yasnippet + elpy-module-django) "Which Elpy modules to use. Elpy can use a number of modules for additional features, which @@ -88,6 +90,8 @@ elpy-module-highlight-indentation) (const :tag "Expand code snippets (YASnippet)" elpy-module-yasnippet) + (const :tag "Django configurations (Elpy-Django)" + elpy-module-django) (const :tag "Configure some sane defaults for Emacs" elpy-module-sane-defaults)) :group 'elpy) @@ -153,7 +157,7 @@ you might want to keep it." :type 'boolean :group 'elpy) - + (defcustom elpy-dedicated-shells nil "Non-nil if Elpy should use dedicated shells. @@ -315,6 +319,18 @@ :type '(repeat string) :group 'elpy) +(defcustom elpy-test-django-runner-manage-command '("manage.py" "test" + "--noinput") + "The command to use for `elpy-test-django-runner' in case we want to use manage.py." + :type '(repeat string) + :group 'elpy) + +(defcustom elpy-test-django-with-manage nil + "Set to nil, elpy will use `elpy-test-django-runner-command', +set to t elpy will use `elpy-test-django-runner-manage-command' and set the project root accordingly." + :type 'boolean + :group 'elpy) + (defcustom elpy-test-nose-runner-command '("nosetests") "The command to use for `elpy-test-nose-runner'." :type '(repeat string) @@ -340,8 +356,15 @@ :type 'boolean :group 'elpy) +(defcustom elpy-syntax-check-command "flake8" + "The command to use for `elpy-check'." + :type 'string + :group 'elpy) + ;;;;;;;;;;;;; ;;; Elpy Mode +(defvar elpy--shell-last-py-buffer nil + "Help keep track of python buffer when changing to pyshell.") (defvar elpy-refactor-map (let ((map (make-sparse-keymap "Refactor"))) @@ -381,7 +404,10 @@ (define-key map (kbd "C-c C-t") 'elpy-test) (define-key map (kbd "C-c C-v") 'elpy-check) (define-key map (kbd "C-c C-z") 'elpy-shell-switch-to-shell) + (define-key map (kbd "C-c C-k") 'elpy-shell-kill) + (define-key map (kbd "C-c C-K") 'elpy-shell-kill-all) (define-key map (kbd "C-c C-r") elpy-refactor-map) + (define-key map (kbd "C-c C-x") elpy-django-mode-map) (define-key map (kbd "<S-return>") 'elpy-open-and-indent-line-below) (define-key map (kbd "<C-S-return>") 'elpy-open-and-indent-line-above) @@ -432,7 +458,11 @@ "Send Buffer to Python") :help "Send the current region or the whole buffer to Python"] ["Send Definition" python-shell-send-defun - :help "Send current definition to Python"]) + :help "Send current definition to Python"] + ["Kill Python shell" elpy-shell-kill + :help "Kill the current Python shell"] + ["Kill all Python shells" elpy-shell-kill-all + :help "Kill all Python shells"]) ("Project" ["Find File" elpy-find-file :help "Interactively find a file in the current project"] @@ -539,6 +569,7 @@ ("Snippets (YASnippet)" yasnippet "yas-") ("Directory Grep (rgrep)" grep "grep-") ("Search as You Type (ido)" ido "ido-") + ("Django Extension" elpy-django "elpy-django-") ;; ffip does not use defcustom ;; highlight-indent does not use defcustom, either. Its sole face ;; is defined in basic-faces. @@ -811,7 +842,8 @@ (not (gethash "rope_version" config)) (not (gethash "jedi_version" config)))) (elpy-insert--para - "There is no backend available. Please install either Rope or Jedi.\n") + "There is no backend available. Please install either Rope or Jedi." + "See https://github.com/jorgenschaefer/elpy/wiki/FAQ#q-should-i-use-rope-or-jedi for guidance.\n") (insert "\n") (widget-create 'elpy-insert--pip-button :package rope-pypi-package) (insert "\n") @@ -898,8 +930,8 @@ :package "yapf" :upgrade t) (insert "\n\n")) - ;; flake8, the default syntax checker, not found - (when (not (executable-find python-check-command)) + ;; Syntax checker not available + (when (not (executable-find elpy-syntax-check-command)) (elpy-insert--para "The configured syntax checker could not be found. Elpy uses this " "program to provide syntax checks of your programs, so you might " @@ -1049,14 +1081,14 @@ yapf-latest)) ("Syntax checker" . ,(let ((syntax-checker (executable-find - python-check-command))) + elpy-syntax-check-command))) (if syntax-checker (format "%s (%s)" (file-name-nondirectory syntax-checker) syntax-checker) (format "Not found (%s)" - python-check-command)))))) + elpy-syntax-check-command)))))) (setq maxwidth 0) (dolist (row table) (when (> (length (car row)) @@ -1601,30 +1633,83 @@ (defun elpy-shell-switch-to-shell () "Switch to inferior Python process buffer." (interactive) + (setq elpy--shell-last-py-buffer (buffer-name)) (pop-to-buffer (process-buffer (elpy-shell-get-or-create-process)))) (defun elpy-shell-switch-to-buffer () "Switch from inferior Python process buffer to recent Python buffer." (interactive) - (pop-to-buffer (other-buffer (current-buffer) 1))) + (pop-to-buffer elpy--shell-last-py-buffer)) + +(defun elpy-shell-kill (&optional kill-buff) + "Kill the current python shell. + +If `elpy-dedicated-shells' is non-nil, +kill the current buffer dedicated shell. + +If KILL-BUFF is non-nil, also kill the associated buffer." + (interactive) + (let ((shell-buffer (python-shell-get-buffer))) + (cond + (shell-buffer + (delete-process shell-buffer) + (when kill-buff + (kill-buffer shell-buffer)) + (message "Killed %s shell" shell-buffer)) + (t + (message "No python shell to kill"))))) + +(defun elpy-shell-kill-all (&optional kill-buffers ask-for-each-one) + "Kill all active python shells. + +If KILL-BUFFERS is non-nil, also kill the associated buffers. +If ASK-FOR-EACH-ONE is non-nil, ask before killing each python process. +" + (interactive) + (let ((python-buffer-list ())) + ;; Get active python shell buffers and kill inactive ones (if asked) + (loop for buffer being the buffers do + (when (string-match "^\*Python\\\[.*\\]\*$" (buffer-name buffer)) + (if (get-buffer-process buffer) + (push buffer python-buffer-list) + (when kill-buffers + (kill-buffer buffer))))) + (cond + ;; Ask for each buffers and kill + ((and python-buffer-list ask-for-each-one) + (loop for buffer in python-buffer-list do + (when (y-or-n-p (format "Kill %s ?" buffer)) + (delete-process buffer) + (when kill-buffers + (kill-buffer buffer))))) + ;; Ask and kill every buffers + (python-buffer-list + (if (y-or-n-p (format "Kill %s python shells ?" (length python-buffer-list))) + (loop for buffer in python-buffer-list do + (delete-process buffer) + (when kill-buffers + (kill-buffer buffer))))) + ;; No shell to close + (t + (message "No python shell to close"))))) (defun elpy-shell-get-or-create-process () "Get or create an inferior Python process for current buffer and return it." (let* ((bufname (format "*%s*" (python-shell-get-process-name nil))) - (dedbufname (format "*%s*" (python-shell-get-process-name t))) - (proc (get-buffer-process bufname)) - (dedproc (get-buffer-process dedbufname))) + (dedbufname (format "*%s*" (python-shell-get-process-name t))) + (proc (get-buffer-process bufname)) + (dedproc (get-buffer-process dedbufname))) (if elpy-dedicated-shells - (if dedproc - dedproc - (run-python (python-shell-parse-command) t) - (get-buffer-process dedbufname)) + (if dedproc + dedproc + (run-python (python-shell-parse-command) t) + (get-buffer-process dedbufname)) (if dedproc - dedproc - (if proc - proc - (run-python (python-shell-parse-command)) - (get-buffer-process bufname)))))) + dedproc + (if proc + proc + (run-python (python-shell-parse-command)) + (get-buffer-process bufname)))))) (defun elpy-shell--region-without-indentation (beg end) "Return the current region as a string, but without indentation." @@ -1672,10 +1757,13 @@ (buffer-file-name)) (buffer-file-name)))) (extra-args (if whole-project-p - (concat " --exclude=" - (mapconcat #'identity - elpy-project-ignored-directories - ",")) + (concat + (if (equal python-check-command "pylint") + " --ignore=" + " --exclude=") + (mapconcat #'identity + elpy-project-ignored-directories + ",")) ""))) (compilation-start (concat python-check-command " " @@ -2041,17 +2129,28 @@ (put 'elpy-test-discover-runner 'elpy-test-runner-p t) (defun elpy-test-django-runner (top file module test) - "Test the project using the Django discover runner. + "Test the project using the Django discover runner, +or with manage.py if elpy-test-django-with-manage is true. This requires Django 1.6 or the django-discover-runner package." (interactive (elpy-test-at-point)) (if module (apply #'elpy-test-run top - (append elpy-test-django-runner-command - (list (if test - (format "%s.%s" module test) - module)))) + (append + ;; if we want to use manage.py, get the root directory where it is. + (if elpy-test-django-with-manage + (append (list (concat (expand-file-name + (locate-dominating-file + (elpy-project-root) + (car elpy-test-django-runner-manage-command))) + (car elpy-test-django-runner-manage-command))) + (cdr elpy-test-django-runner-manage-command)) + ;; or the default: + elpy-test-django-runner-command) + (list (if test + (format "%s.%s" module test) + module)))) (apply #'elpy-test-run top elpy-test-django-runner-command))) @@ -2204,7 +2303,7 @@ ;;;;;;;;;;;;;;;;;;;;;;; ;;; Import manipulation -(defun elpy-importmagic--add-import-read-args (&optional object prompt) +(defun elpy-importmagic--add-import-read-args (&optional object prompt ask-for-alias) (let* ((default-object (save-excursion (let ((bounds (with-syntax-table python-dotty-syntax-table (bounds-of-thing-at-point 'symbol)))) @@ -2217,24 +2316,29 @@ (cond ;; An elpy warning (i.e. index not ready) is returned as a string. ((stringp possible-imports) - (list "")) + "") ;; If there is no candidate, we exit immediately. ((null possible-imports) (message "No import candidate found") - (list "")) + "") ;; We have some candidates, let the user choose one. (t - (let ((first-choice (car possible-imports)) - (user-choice (completing-read statement-prompt possible-imports))) - (list (if (equal user-choice "") first-choice user-choice))))))) - -(defun elpy-importmagic-add-import (statement) - "Prompt to import thing at point, show possbile imports and add selected import." - (interactive (elpy-importmagic--add-import-read-args)) - (unless (equal statement "") - (let* ((res (elpy-rpc "add_import" (list buffer-file-name - (elpy-rpc--buffer-contents) - statement)))) + (let* ((first-choice (car possible-imports)) + (user-choice (completing-read statement-prompt possible-imports)) + (alias (if ask-for-alias (read-string (format "Import \"%s\" as: " object-to-import)) ""))) + (concat (if (equal user-choice "") first-choice user-choice) + (if (not (or (equal alias "") (equal alias object-to-import))) (concat " as " alias)))))))) + +(defun elpy-importmagic-add-import (&optional statement ask-for-alias) + "Prompt to import thing at point, show possible imports and add selected import. + +With prefix arg, also ask for an import alias." + (interactive "i\nP") + (let* ((statement (or statement (elpy-importmagic--add-import-read-args nil nil ask-for-alias))) + (res (elpy-rpc "add_import" (list buffer-file-name + (elpy-rpc--buffer-contents) + statement)))) + (unless (equal statement "") (elpy-buffer--replace-block res)))) (defun elpy-importmagic-fixup () @@ -2244,13 +2348,24 @@ (interactive) ;; get all unresolved names, and interactively add imports for them (let* ((res (elpy-rpc "get_unresolved_symbols" (list buffer-file-name - (elpy-rpc--buffer-contents))))) + (elpy-rpc--buffer-contents)))) + (unresolved-aliases (list))) (unless (stringp res) (if (null res) (message "No imports to add.")) (dolist (object res) (let* ((prompt (format "How to import \"%s\": " object)) - (choice (elpy-importmagic--add-import-read-args object prompt))) - (elpy-importmagic-add-import (car choice)))))) + (choice (elpy-importmagic--add-import-read-args object prompt nil))) + (when (equal choice "") + (add-to-list 'unresolved-aliases (car (split-string object "\\.")))) + (elpy-importmagic-add-import choice nil)))) + ;; ask for unresolved aliases real names and add import for them + (dolist (alias unresolved-aliases) + (let* ((object (read-string (format "Real name of \"%s\" alias: " alias nil))) + (prompt (format "How to import \"%s\": " object)) + (choice (concat + (elpy-importmagic--add-import-read-args object prompt nil) + (concat " as " alias)))) + (elpy-importmagic-add-import choice nil)))) ;; now get a new import statement block (this also sorts) (let* ((res (elpy-rpc "remove_unreferenced_imports" (list buffer-file-name (elpy-rpc--buffer-contents))))) @@ -2288,14 +2403,18 @@ (if (use-region-p) (let ((new-block (elpy-rpc method (list (elpy-rpc--region-contents)))) (beg (region-beginning)) (end (region-end))) - (elpy-buffer--replace-region beg end new-block)) + (elpy-buffer--replace-region + beg end + (replace-regexp-in-string "\n$" "" new-block)) + (goto-char end) + (deactivate-mark)) ;; Vector instead of list, json.el in Emacs 24.3 and before ;; breaks for single-element lists of alists. (let ((new-block (elpy-rpc method (vector (elpy-rpc--buffer-contents)))) (beg (point-min)) (end (point-max))) - (elpy-buffer--replace-region beg end new-block))) - (forward-line (1- line)) - (forward-char col))) + (elpy-buffer--replace-region beg end new-block) + (forward-line (1- line)) + (forward-char col))))) ;;;;;;;;;;;;;; ;;; Multi-Edit @@ -3218,7 +3337,7 @@ "Remove the lighter for MODE-NAME. It should not be necessary to see (Python Elpy yas company ElDoc) all the -time. +time. If you need your modeline, you can set the variable `elpy-remove-modeline-lighter' to nil " @@ -3571,10 +3690,7 @@ (require 'flymake) (elpy-modules-remove-modeline-lighter 'flymake-mode) ;; Flymake support using flake8, including warning faces. - (when (and (executable-find "flake8") - (equal python-check-command - (elpy-flymake--standard-value 'python-check-command))) - (setq python-check-command "flake8")) + (setq python-check-command elpy-syntax-check-command) ;; Add our initializer function (add-to-list 'flymake-allowed-file-name-masks @@ -3655,13 +3771,6 @@ err-info ", "))))) -(defun elpy-flymake--standard-value (var) - "Return the standard value of the given variable." - (let ((sv (get var 'standard-value))) - (when (consp sv) - (ignore-errors - (eval (car sv)))))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Module: Highlight Indentation @@ -3720,6 +3829,17 @@ (yas-minor-mode -1)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Module: Elpy-Django + +(defun elpy-module-django (command &rest args) + "Module to provide Django support." + (pcase command + (`buffer-init + (elpy-django-setup)) + (`buffer-stop + (elpy-django -1)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Backwards compatibility ;; Functions for Emacs 24 before 24.3