;;; +django-tests.el -*- lexical-binding: t; -*- (require 'projectile) (require 'python) (require 'subr-x) (defun django--project-root () (or (projectile-project-root) (user-error "Not in a Projectile project"))) (defun django--module-from-file (file root) (let* ((rel (file-relative-name file root)) (no-ext (file-name-sans-extension rel))) (replace-regexp-in-string "/" "." no-ext))) (defun django--def-name-at-point () (save-excursion (when (ignore-errors (python-nav-beginning-of-defun) t) (when (looking-at (rx bol (* space) "def" (+ space) (group (+ (or word ?_))) (* space) "(")) (match-string-no-properties 1))))) (defun django--enclosing-class-name () (save-excursion (let ((found nil) (limit (point-min))) (while (and (not found) (> (point) limit)) (python-nav-beginning-of-statement) (when (looking-at (rx bol (* space) "class" (+ space) (group (+ (or word ?_))))) (setq found (match-string-no-properties 1))) (condition-case _err (python-nav-backward-block) (error (goto-char limit)))) found))) (defun django--selector-at-point () (let ((fn (django--def-name-at-point)) (cls (django--enclosing-class-name))) (cond ((and fn (string-prefix-p "test_" fn)) (if cls (format "%s.%s" cls fn) fn)) (cls cls) (t nil)))) (defun django-run-tests (&optional module selector) (interactive) (let* ((module-part (or module "")) (selector-part (if selector (concat "." selector) "")) (param (string-trim (concat module-part selector-part))) (command (format "python manage.py test %s" param))) (message "Running command: %s" command) (projectile-run-async-shell-command-in-root command "*Django tests*"))) (defun django-run-test-at-point () (interactive) (let* ((root (django--project-root)) (file (or (buffer-file-name) (user-error "Buffer is not visiting a file"))) (module (django--module-from-file file root)) (sel (django--selector-at-point))) (django-run-tests module sel))) (defun django-run-tests-for-current-file () (interactive) (let* ((root (django--project-root)) (file (or (buffer-file-name) (user-error "Buffer is not visiting a file"))) (module (django--module-from-file file root))) (django-run-tests module nil))) (provide '+django-tests)