I don't remember exactly why I needed all this magic, but I think the
flymake-create-temp-intempfunction is needed to get Flymake to work with TRAMP; it makes flymake put the temporary file on the local machine instead of the remote one, where Pyflakes (running locally) can see it. The rest is just standard stuff to tell flymake to use Pyflakes with Python code.
;; pyflakes ;; adapted from http://plope.com/Members/chrism/flymake-mode ;; and http://www.emacswiki.org/emacs/FlymakeRuby (defun flymake-create-temp-intemp (file-name prefix) "Return file name in temporary directory for checking FILE-NAME. This is a replacement for `flymake-create-temp-inplace'. The difference is that it gives a file name in `temporary-file-directory' instead of the same directory as FILE-NAME. For the use of PREFIX see that function. Note that not making the temporary file in another directory \(like here) will not if the file you are checking depends on relative paths to other files \(for the type of checks flymake makes)." (unless (stringp file-name) (error "Invalid file-name")) (or prefix (setq prefix "flymake")) (let* ((name (concat (file-name-nondirectory (file-name-sans-extension file-name)) "_" prefix)) (ext (concat "." (file-name-extension file-name))) (temp-name (make-temp-file name nil ext)) ) (flymake-log 3 "create-temp-intemp: file=%s temp=%s" file-name temp-name) temp-name)) (when (load "flymake" t) (defun flymake-pyflakes-init () (let* ((temp-file (flymake-init-create-temp-buffer-copy 'flymake-create-temp-intemp)) (local-file (file-relative-name temp-file (file-name-directory buffer-file-name)))) (flymake-log 3 "flymake-pyflakes-init: dir=%s %s" buffer-file-name (file-name-directory temp-file)) (list "pyflakes" (list local-file) (file-name-directory temp-file)))) (add-to-list 'flymake-allowed-file-name-masks '("\\.py\\'" flymake-pyflakes-init))) (add-hook 'find-file-hook 'flymake-find-file-hook)