For my Emacs Python environment, I recently switched from Elpy
to lsp-mode
too. Mainly to benefit from the dap-mode
debugger and a better "Find definition" functionality (able to find a definition in the virtual environement libraries). And also because the great Elpy
package is not maintained anymore.
But what I was still missing from Elpy
, was the ability to quickly run the tests as @Mittenchops pointed it out.
As I couldn't find any package to easily fix that, I wrote my own Elisp
functions : django-run-all-tests
, django-run-buffer-tests
, and django-run-test-at-point
(the last one inspired by the Elpy one).
These work well assuming :
- it is a
Django
project (else the test runner command needs to be adapted)
- tests are in a single directory that have to configured with
django-tests-dir-name
variable relatively to the project root ((setq django-tests-dir-name "tests")
for example)
projectile
package is installed (needed to retrieve project root)
;; Copy of elpy-test--current-test-name function from Elpy project
;; https://github.com/jorgenschaefer/elpy
(defun django-get-test-name-at-point ()
"Return the name of the test at point."
(let ((name (python-info-current-defun)))
(if (and name (string-match "\\`\\([^.]+\\.[^.]+\\)\\." name)) (match-string 1 name) name)))
(defun django-get-module ()
(file-name-sans-extension (buffer-name)))
(defun django-run-tests (&optional module test)
(let* ((dir-part django-tests-dir-name)
(module-part (if module (concat "." module) ""))
(test-part (if test (concat "." test) ""))
(param (concat dir-part module-part test-part))
(command (format "./manage.py test %s --keepdb" param)))
(message command)
(projectile-run-async-shell-command-in-root command)))
(defun django-run-all-tests ()
"Run all Django api tests."
(interactive)
(django-run-tests))
(defun django-run-buffer-tests ()
"Run Django api tests for current buffer."
(interactive)
(let ((module (django-get-module)))
(django-run-tests module)))
(defun django-run-test-at-point ()
"Run Django api test at point."
(interactive)
(let ((module (django-get-module))
(test (django-get-test-name-at-point)))
(django-run-tests module test)))
Put this code in your init.el
file. An example using use-package
package and adding some key bindings to the Python mode :
(use-package python
:bind (:map python-mode-map (("C-c t a" . django-run-all-tests)
("C-c t f" . django-run-buffer-tests)
("C-c t p" . django-run-test-at-point)))
:config
;; Past the functions here
)