import文からファイルに飛びたい。

探せばもっと良いものがあるのだろうけれど、とりあえず欲しくなったので書いた。
emacs-lisp正規表現に先読みは無かったかな?(正規表現に一部気になる嫌なところがある)
(まだ、手元の環境にとても依存しているかも。動かないかも)

;; (defmacro python-ex:and-let*
;;   (bindings &rest body)
;;   "imported from srfi-2"
;;   (reduce (function
;;            (lambda (binding r)
;;              (let ((head (car binding)))
;;                (cond ((and (atom head) (symbolp head))
;;                       (\` (let ((\, binding)) (when (\, head) (\, r)))))
;;                      ((listp head)
;;                       (\` (when (\, head) (\, r))))
;;                      (t (error "and-let*: invalid head %s" head))))))
;;           bindings
;;           :from-end
;;           t
;;           :initial-value
;;           (\` (progn (\,@ body)))))
;; (put 'python-ex:and-let* 'lisp-indent-function 1)

(defvar python-ex:module-tokens-regexp "[^ .]+\\(\\.[^ .]+\\)*")

(defun python-ex:module-tokens-in-current-line ()
  "[maybe] return match object or nil"
  (save-excursion
    (let ((rx (format "^[ \t]*\\(from +\\(%s\\) +import +[^ ]+\\|import +\\(%s\\)\\)"
                               python-ex:module-tokens-regexp
                               python-ex:module-tokens-regexp
                               )))
      (goto-char (point-at-bol))
      (and (re-search-forward rx  (point-at-eol) t 1)
           (or (match-string-no-properties 4)
               (match-string-no-properties 2))))))

 (defun python-ex:module->path (module &optional force-reload-p)
   (python-ex:let1 path (replace-regexp-in-string "\\." "/" module)
     (loop for dir in (python-ex:sys-path force-reload-p)
           for d = (concat dir "/" path)
           if (file-exists-p d)
           return d
           else
           for file = (concat d ".py")
           when (file-exists-p file)
           return file)))

(defun python-ex:current-library-path ()
  "[maybe] return current library path from import sentence"
  (and-let* ((module (python-ex:module-tokens-in-current-line)))
    (python-ex:module->path (python-ex:module-tokens-in-current-line))))

(defun python-ex:ffap/import-sentence (other-frame-p) (interactive "P")
  "ffap for import sentence"
  (and-let* ((path (python-ex:current-library-path)))
    (cond (other-frame-p (find-file-other-frame path))
          (t (find-file path)))))


(define-key python-mode-map "\C-c\C-f" 'python-ex:ffap/import-sentence)

利用

import文にカーソルを合わせてC-c C-fをすると、対応したファイルに飛ぶ。。。はず。
(virtualenvとか使っている場合は無理かも)

#!/usr/bin/env python
from django.core.management import execute_manager ;;この行にカーソルを合わせてC-c C-f
try:
    import settings # Assumed to be in the same directory.
except ImportError:
    import sys
    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
    sys.exit(1)

if __name__ == "__main__":
    execute_manager(settings)