diff options
-rw-r--r-- | README.rst | 6 | ||||
-rw-r--r-- | doc/development_guide/api/index.rst | 3 | ||||
-rw-r--r-- | doc/user_guide/installation/ide_integration/flymake-emacs.rst | 10 | ||||
-rw-r--r-- | doc/whatsnew/fragments/7737.other | 5 | ||||
-rw-r--r-- | elisp/pylint-flymake.el | 15 | ||||
-rw-r--r-- | elisp/pylint.el | 255 | ||||
-rw-r--r-- | elisp/startup | 17 | ||||
-rw-r--r-- | pylint/__init__.py | 7 | ||||
-rwxr-xr-x | pylint/epylint.py | 11 | ||||
-rw-r--r-- | tests/test_epylint.py | 27 | ||||
-rw-r--r-- | tests/test_pylint_runners.py | 30 |
11 files changed, 70 insertions, 316 deletions
diff --git a/README.rst b/README.rst index fd7267a29..f41ad3e23 100644 --- a/README.rst +++ b/README.rst @@ -86,11 +86,15 @@ Pylint ships with three additional tools: - pyreverse_ (standalone tool that generates package and class diagrams.) - symilar_ (duplicate code finder that is also integrated in pylint) -- epylint_ (Emacs and Flymake compatible Pylint) .. _pyreverse: https://pylint.pycqa.org/en/latest/pyreverse.html .. _symilar: https://pylint.pycqa.org/en/latest/symilar.html + +The epylint_ Emacs package, which includes Flymake support, is now maintained +in `its own repository`_. + .. _epylint: https://pylint.pycqa.org/en/latest/user_guide/ide_integration/flymake-emacs.html +.. _its own repository: https://github.com/emacsorphanage/pylint Projects that you might want to use alongside pylint include flake8_ (faster and simpler checks with very few false positives), mypy_, pyright_ or pyre_ (typing checks), bandit_ (security diff --git a/doc/development_guide/api/index.rst b/doc/development_guide/api/index.rst index 373c49866..00e6e1a9f 100644 --- a/doc/development_guide/api/index.rst +++ b/doc/development_guide/api/index.rst @@ -7,10 +7,9 @@ Python program thanks to their APIs: .. sourcecode:: python - from pylint import run_pylint, run_epylint, run_pyreverse, run_symilar + from pylint import run_pylint, run_pyreverse, run_symilar run_pylint("--disable=C", "myfile.py") - run_epylint(...) run_pyreverse(...) run_symilar(...) diff --git a/doc/user_guide/installation/ide_integration/flymake-emacs.rst b/doc/user_guide/installation/ide_integration/flymake-emacs.rst index 44b9b3262..79310ff59 100644 --- a/doc/user_guide/installation/ide_integration/flymake-emacs.rst +++ b/doc/user_guide/installation/ide_integration/flymake-emacs.rst @@ -4,12 +4,10 @@ Using Pylint through Flymake in Emacs ===================================== .. warning:: - If you're reading this doc and are actually using flymake please - open a support question at https://github.com/PyCQA/pylint/issues/new/choose - and tell us, we don't have any maintainers for emacs and are thinking about - dropping the support. - -.. TODO 3.0, do we still need to support flymake ? + The Emacs package now has its own repository and is looking for a maintainer. + If you're reading this doc and are interested in maintaining this package or + are actually using flymake please open an issue at + https://github.com/emacsorphanage/pylint/issues/new/choose To enable Flymake for Python, insert the following into your .emacs: diff --git a/doc/whatsnew/fragments/7737.other b/doc/whatsnew/fragments/7737.other new file mode 100644 index 000000000..7b7988759 --- /dev/null +++ b/doc/whatsnew/fragments/7737.other @@ -0,0 +1,5 @@ +epylint is now deprecated and will be removed in pylint 3.0.0. All emacs and flymake related +files were removed and their support will now happen in an external repository : +https://github.com/emacsorphanage/pylint. + +Closes #7737 diff --git a/elisp/pylint-flymake.el b/elisp/pylint-flymake.el deleted file mode 100644 index ed213bf46..000000000 --- a/elisp/pylint-flymake.el +++ /dev/null @@ -1,15 +0,0 @@ -;; Configure Flymake for python -(when (load "flymake" t) - (defun flymake-pylint-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-inplace)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "epylint" (list local-file)))) - - (add-to-list 'flymake-allowed-file-name-masks - '("\\.py\\'" flymake-pylint-init))) - -;; Set as a minor mode for python -(add-hook 'python-mode-hook '(lambda () (flymake-mode))) diff --git a/elisp/pylint.el b/elisp/pylint.el deleted file mode 100644 index 327da0fcb..000000000 --- a/elisp/pylint.el +++ /dev/null @@ -1,255 +0,0 @@ -;;; pylint.el --- minor mode for running `pylint' - -;; Copyright (c) 2009, 2010 Ian Eure <ian.eure@gmail.com> -;; Author: Ian Eure <ian.eure@gmail.com> -;; Maintainer: Jonathan Kotta <jpkotta@gmail.com> - -;; Keywords: languages python -;; Version: 1.02 - -;; pylint.el is free software; you can redistribute it and/or modify it -;; under the terms of the GNU General Public License as published by the Free -;; Software Foundation; either version 2, or (at your option) any later -;; version. -;; -;; It is distributed in the hope that it will be useful, but WITHOUT ANY -;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -;; details. -;; -;; You should have received a copy of the GNU General Public License along -;; with your copy of Emacs; see the file COPYING. If not, write to the Free -;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -;; MA 02110-1301, USA - -;;; Commentary: -;; -;; Specialized compile mode for pylint. You may want to add the -;; following to your init.el: -;; -;; (autoload 'pylint "pylint") -;; (add-hook 'python-mode-hook 'pylint-add-menu-items) -;; (add-hook 'python-mode-hook 'pylint-add-key-bindings) -;; -;; There is also a handy command `pylint-insert-ignore-comment' that -;; makes it easy to insert comments of the form `# pylint: -;; ignore=msg1,msg2,...'. - -;;; Code: - -(require 'compile) -(require 'tramp) - -(defgroup pylint nil - "Minor mode for running the Pylint Python checker" - :prefix "pylint-" - :group 'tools - :group 'languages) - -(defvar pylint-last-buffer nil - "The most recent PYLINT buffer. -A PYLINT buffer becomes most recent when you select PYLINT mode in it. -Notice that using \\[next-error] or \\[compile-goto-error] modifies -`completion-last-buffer' rather than `pylint-last-buffer'.") - -(defconst pylint-regexp-alist - (let ((base "^\\(.*\\):\\([0-9]+\\):\s+\\(\\[%s.*\\)$")) - (list - (list (format base "[FE]") 1 2) - (list (format base "[RWC]") 1 2 nil 1))) - "Regexp used to match PYLINT hits. See `compilation-error-regexp-alist'.") - -(defcustom pylint-options '("--reports=n" "--output-format=parseable") - "Options to pass to pylint.py" - :type '(repeat string) - :group 'pylint) - -(defcustom pylint-use-python-indent-offset nil - "If non-nil, use `python-indent-offset' to set indent-string." - :type 'boolean - :group 'pylint) - -(defcustom pylint-command "pylint" - "PYLINT command." - :type '(file) - :group 'pylint) - -(defcustom pylint-alternate-pylint-command "pylint2" - "Command for pylint when invoked with C-u." - :type '(file) - :group 'pylint) - -(defcustom pylint-ask-about-save nil - "Non-nil means \\[pylint] asks which buffers to save before compiling. -Otherwise, it saves all modified buffers without asking." - :type 'boolean - :group 'pylint) - -(defvar pylint--messages-list () - "A list of strings of all pylint messages.") - -(defvar pylint--messages-list-hist () - "Completion history for `pylint--messages-list'.") - -(defun pylint--sort-messages (a b) - "Compare function for sorting `pylint--messages-list'. - -Sorts most recently used elements first using `pylint--messages-list-hist'." - (let ((idx 0) - (a-idx most-positive-fixnum) - (b-idx most-positive-fixnum)) - (dolist (e pylint--messages-list-hist) - (when (string= e a) - (setq a-idx idx)) - (when (string= e b) - (setq b-idx idx)) - (setq idx (1+ idx))) - (< a-idx b-idx))) - -(defun pylint--create-messages-list () - "Use `pylint-command' to populate `pylint--messages-list'." - ;; example output: - ;; |--we want this--| - ;; v v - ;; :using-cmp-argument (W1640): *Using the cmp argument for list.sort / sorted* - ;; Using the cmp argument for list.sort or the sorted builtin should be avoided, - ;; since it was removed in Python 3. Using either `key` or `functools.cmp_to_key` - ;; should be preferred. This message can't be emitted when using Python >= 3.0. - (setq pylint--messages-list - (split-string - (with-temp-buffer - (shell-command (concat pylint-command " --list-msgs") (current-buffer)) - (flush-lines "^[^:]") - (goto-char (point-min)) - (while (not (eobp)) - (delete-char 1) ;; delete ";" - (re-search-forward " ") - (delete-region (point) (line-end-position)) - (forward-line 1)) - (buffer-substring-no-properties (point-min) (point-max)))))) - -;;;###autoload -(defun pylint-insert-ignore-comment (&optional arg) - "Insert a comment like \"# pylint: disable=msg1,msg2,...\". - -This command repeatedly uses `completing-read' to match known -messages, and ultimately inserts a comma-separated list of all -the selected messages. - -With prefix argument, only insert a comma-separated list (for -appending to an existing list)." - (interactive "*P") - (unless pylint--messages-list - (pylint--create-messages-list)) - (setq pylint--messages-list - (sort pylint--messages-list #'pylint--sort-messages)) - (let ((msgs ()) - (msg "") - (prefix (if arg - "," - "# pylint: disable=")) - (sentinel "[DONE]")) - (while (progn - (setq msg (completing-read - "Message: " - pylint--messages-list - nil t nil 'pylint--messages-list-hist sentinel)) - (unless (string= sentinel msg) - (add-to-list 'msgs msg 'append)))) - (setq pylint--messages-list-hist - (delete sentinel pylint--messages-list-hist)) - (insert prefix (mapconcat 'identity msgs ",")))) - -(define-compilation-mode pylint-mode "PYLINT" - (setq pylint-last-buffer (current-buffer)) - (set (make-local-variable 'compilation-error-regexp-alist) - pylint-regexp-alist) - (set (make-local-variable 'compilation-disable-input) t)) - -(defvar pylint-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map compilation-minor-mode-map) - (define-key map " " 'scroll-up) - (define-key map "\^?" 'scroll-down) - (define-key map "\C-c\C-f" 'next-error-follow-minor-mode) - - (define-key map "\r" 'compile-goto-error) ;; ? - (define-key map "n" 'next-error-no-select) - (define-key map "p" 'previous-error-no-select) - (define-key map "{" 'compilation-previous-file) - (define-key map "}" 'compilation-next-file) - (define-key map "\t" 'compilation-next-error) - (define-key map [backtab] 'compilation-previous-error) - map) - "Keymap for PYLINT buffers. -`compilation-minor-mode-map' is a cdr of this.") - -(defun pylint--make-indent-string () - "Make a string for the `--indent-string' option." - (format "--indent-string='%s'" - (make-string python-indent-offset ?\ ))) - -;;;###autoload -(defun pylint (&optional arg) - "Run PYLINT, and collect output in a buffer, much like `compile'. - -While pylint runs asynchronously, you can use \\[next-error] (M-x next-error), -or \\<pylint-mode-map>\\[compile-goto-error] in the grep \ -output buffer, to go to the lines where pylint found matches. - -\\{pylint-mode-map}" - (interactive "P") - - (save-some-buffers (not pylint-ask-about-save) nil) - (let* ((filename (buffer-file-name)) - (localname-offset (cl-struct-slot-offset 'tramp-file-name 'localname)) - (filename (or (and (tramp-tramp-file-p filename) - (elt (tramp-dissect-file-name filename) localname-offset)) - filename)) - (filename (shell-quote-argument filename)) - (pylint-command (if arg - pylint-alternate-pylint-command - pylint-command)) - (pylint-options (if (not pylint-use-python-indent-offset) - pylint-options - (append pylint-options - (list (pylint--make-indent-string))))) - (command (mapconcat - 'identity - (append `(,pylint-command) pylint-options `(,filename)) - " "))) - - (compilation-start command 'pylint-mode))) - -;;;###autoload -(defun pylint-add-key-bindings () - (let ((map (cond - ((boundp 'py-mode-map) py-mode-map) - ((boundp 'python-mode-map) python-mode-map)))) - - ;; shortcuts in the tradition of python-mode and ropemacs - (define-key map (kbd "C-c m l") 'pylint) - (define-key map (kbd "C-c m p") 'previous-error) - (define-key map (kbd "C-c m n") 'next-error) - (define-key map (kbd "C-c m i") 'pylint-insert-ignore-comment) - nil)) - -;;;###autoload -(defun pylint-add-menu-items () - (let ((map (cond - ((boundp 'py-mode-map) py-mode-map) - ((boundp 'python-mode-map) python-mode-map)))) - - (define-key map [menu-bar Python pylint-separator] - '("--" . pylint-separator)) - (define-key map [menu-bar Python next-error] - '("Next error" . next-error)) - (define-key map [menu-bar Python prev-error] - '("Previous error" . previous-error)) - (define-key map [menu-bar Python lint] - '("Pylint" . pylint)) - nil)) - -(provide 'pylint) - -;;; pylint.el ends here diff --git a/elisp/startup b/elisp/startup deleted file mode 100644 index 2f8fed1d4..000000000 --- a/elisp/startup +++ /dev/null @@ -1,17 +0,0 @@ -;; -*-emacs-lisp-*- -;; -;; Emacs startup file for the Debian GNU/Linux %PACKAGE% package -;; -;; Originally contributed by Nils Naumann <naumann@unileoben.ac.at> -;; Modified by Dirk Eddelbuettel <edd@debian.org> -;; Adapted for dh-make by Jim Van Zandt <jrv@vanzandt.mv.com> - -;; The %PACKAGE% package follows the Debian/GNU Linux 'emacsen' policy and -;; byte-compiles its elisp files for each 'Emacs flavor' (emacs19, -;; xemacs19, emacs20, xemacs20...). The compiled code is then -;; installed in a subdirectory of the respective site-lisp directory. -;; We have to add this to the load-path: -(setq load-path (cons (concat "/usr/share/" - (symbol-name debian-emacs-flavor) - "/site-lisp/%PACKAGE%") load-path)) -(load-library "pylint") diff --git a/pylint/__init__.py b/pylint/__init__.py index ab5fd42ab..2cc7edadb 100644 --- a/pylint/__init__.py +++ b/pylint/__init__.py @@ -16,6 +16,7 @@ __all__ = [ import os import sys +import warnings from collections.abc import Sequence from typing import NoReturn @@ -54,6 +55,12 @@ def run_epylint(argv: Sequence[str] | None = None) -> NoReturn: """ from pylint.epylint import Run as EpylintRun + warnings.warn( + "'run_epylint' will be removed in pylint 3.0, use " + "https://github.com/emacsorphanage/pylint instead.", + DeprecationWarning, + stacklevel=1, + ) EpylintRun(argv) diff --git a/pylint/epylint.py b/pylint/epylint.py index b6b6bf402..a69ce0d87 100755 --- a/pylint/epylint.py +++ b/pylint/epylint.py @@ -41,6 +41,7 @@ from __future__ import annotations import os import shlex import sys +import warnings from collections.abc import Sequence from io import StringIO from subprocess import PIPE, Popen @@ -168,6 +169,11 @@ def py_run( To silently run Pylint on a module, and get its standard output and error: >>> (pylint_stdout, pylint_stderr) = py_run( 'module_name.py', True) """ + warnings.warn( + "'epylint' will be removed in pylint 3.0, use https://github.com/emacsorphanage/pylint instead.", + DeprecationWarning, + stacklevel=2, + ) # Detect if we use Python as executable or not, else default to `python` executable = sys.executable if "python" in sys.executable else "python" @@ -198,6 +204,11 @@ def py_run( def Run(argv: Sequence[str] | None = None) -> NoReturn: + warnings.warn( + "'epylint' will be removed in pylint 3.0, use https://github.com/emacsorphanage/pylint instead.", + DeprecationWarning, + stacklevel=2, + ) if not argv and len(sys.argv) == 1: print(f"Usage: {sys.argv[0]} <filename> [options]") sys.exit(1) diff --git a/tests/test_epylint.py b/tests/test_epylint.py index e1b090395..7e9116e99 100644 --- a/tests/test_epylint.py +++ b/tests/test_epylint.py @@ -25,12 +25,12 @@ def example_path(tmp_path: PosixPath) -> PosixPath: def test_epylint_good_command(example_path: PosixPath) -> None: - out, err = lint.py_run( - # pylint: disable-next=consider-using-f-string - "%s -E --disable=E1111 --msg-template '{category} {module} {obj} {line} {column} {msg}'" - % example_path, - return_std=True, - ) + with pytest.warns(DeprecationWarning): + out, _ = lint.py_run( + f"{example_path} -E --disable=E1111 --msg-template " + "'{category} {module} {obj} {line} {column} {msg}'", + return_std=True, + ) msg = out.read() assert ( msg @@ -39,16 +39,16 @@ def test_epylint_good_command(example_path: PosixPath) -> None: error my_app IvrAudioApp.run 4 8 Instance of 'IvrAudioApp' has no 'hassan' member """ ) - assert err.read() == "" def test_epylint_strange_command(example_path: PosixPath) -> None: - out, err = lint.py_run( - # pylint: disable-next=consider-using-f-string - "%s -E --disable=E1111 --msg-template={category} {module} {obj} {line} {column} {msg}" - % example_path, - return_std=True, - ) + with pytest.warns(DeprecationWarning): + out, _ = lint.py_run( + # pylint: disable-next=consider-using-f-string + "%s -E --disable=E1111 --msg-template={category} {module} {obj} {line} {column} {msg}" + % example_path, + return_std=True, + ) assert ( out.read() == """\ @@ -66,4 +66,3 @@ def test_epylint_strange_command(example_path: PosixPath) -> None: error """ ) - assert err.read() == "" diff --git a/tests/test_pylint_runners.py b/tests/test_pylint_runners.py index 8e68f8eaa..8d6930535 100644 --- a/tests/test_pylint_runners.py +++ b/tests/test_pylint_runners.py @@ -33,9 +33,7 @@ class _RunCallable(Protocol): # pylint: disable=too-few-public-methods ... -@pytest.mark.parametrize( - "runner", [run_epylint, run_pylint, run_pyreverse, run_symilar] -) +@pytest.mark.parametrize("runner", [run_pylint, run_pyreverse, run_symilar]) def test_runner(runner: _RunCallable, tmpdir: LocalPath) -> None: filepath = os.path.abspath(__file__) testargs = ["", filepath] @@ -46,9 +44,18 @@ def test_runner(runner: _RunCallable, tmpdir: LocalPath) -> None: assert err.value.code == 0 -@pytest.mark.parametrize( - "runner", [run_epylint, run_pylint, run_pyreverse, run_symilar] -) +def test_epylint(tmpdir: LocalPath) -> None: + """TODO: 3.0 delete with epylint.""" + filepath = os.path.abspath(__file__) + with tmpdir.as_cwd(): + with patch.object(sys, "argv", ["", filepath]): + with pytest.raises(SystemExit) as err: + with pytest.warns(DeprecationWarning): + run_epylint() + assert err.value.code == 0 + + +@pytest.mark.parametrize("runner", [run_pylint, run_pyreverse, run_symilar]) def test_runner_with_arguments(runner: _RunCallable, tmpdir: LocalPath) -> None: """Check the runners with arguments as parameter instead of sys.argv.""" filepath = os.path.abspath(__file__) @@ -59,6 +66,17 @@ def test_runner_with_arguments(runner: _RunCallable, tmpdir: LocalPath) -> None: assert err.value.code == 0 +def test_epylint_with_arguments(tmpdir: LocalPath) -> None: + """TODO: 3.0 delete with epylint.""" + filepath = os.path.abspath(__file__) + testargs = [filepath] + with tmpdir.as_cwd(): + with pytest.raises(SystemExit) as err: + with pytest.warns(DeprecationWarning): + run_epylint(testargs) + assert err.value.code == 0 + + def test_pylint_argument_deduplication( tmpdir: LocalPath, tests_directory: pathlib.Path ) -> None: |