Merge from emacs-23
[bpt/emacs.git] / lisp / progmodes / python.el
index 9057e51..7754dc6 100644 (file)
@@ -1,6 +1,7 @@
 ;;; python.el --- silly walks for Python  -*- coding: iso-8859-1 -*-
 
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: Dave Love <fx@gnu.org>
 ;; Maintainer: FSF
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs 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 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;; Major mode for editing Python, with support for inferior processes.
 
-;; There is another Python mode, python-mode.el, used by XEmacs and
-;; maintained with Python.  That isn't covered by an FSF copyright
-;; assignment, unlike this code, and seems not to be well-maintained
-;; for Emacs (though I've submitted fixes).  This mode is rather
-;; simpler and is better in other ways.  In particular, using the
-;; syntax functions with text properties maintained by font-lock makes
-;; it more correct with arbitrary string and comment contents.
+;; There is another Python mode, python-mode.el:
+;; http://launchpad.net/python-mode
+;; used by XEmacs, and originally maintained with Python.
+;; That isn't covered by an FSF copyright assignment (?), unlike this
+;; code, and seems not to be well-maintained for Emacs (though I've
+;; submitted fixes).  This mode is rather simpler and is better in
+;; other ways.  In particular, using the syntax functions with text
+;; properties maintained by font-lock makes it more correct with
+;; arbitrary string and comment contents.
 
 ;; This doesn't implement all the facilities of python-mode.el.  Some
 ;; just need doing, e.g. catching exceptions in the inferior Python
@@ -44,7 +45,7 @@
 ;; `forward-into-nomenclature' should be done separately, since it's
 ;; not specific to Python, and I've installed a minor mode to do the
 ;; job properly in Emacs 23.  [CC mode 5.31 contains an incompatible
-;; feature, `c-subword-mode' which is intended to have a similar
+;; feature, `subword-mode' which is intended to have a similar
 ;; effect, but actually only affects word-oriented keybindings.]
 
 ;; Other things seem more natural or canonical here, e.g. the
@@ -72,7 +73,6 @@
   (require 'compile)
   (require 'hippie-exp))
 
-(require 'sym-comp)
 (autoload 'comint-mode "comint")
 
 (defgroup python nil
   :link '(emacs-commentary-link "python"))
 \f
 ;;;###autoload
-(add-to-list 'interpreter-mode-alist '("jython" . jython-mode))
+(add-to-list 'interpreter-mode-alist (cons (purecopy "jython") 'jython-mode))
 ;;;###autoload
-(add-to-list 'interpreter-mode-alist '("python" . python-mode))
+(add-to-list 'interpreter-mode-alist (cons (purecopy "python") 'python-mode))
 ;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
-(add-to-list 'same-window-buffer-names "*Python*")
+(add-to-list 'auto-mode-alist (cons (purecopy "\\.py\\'")  'python-mode))
+(add-to-list 'same-window-buffer-names (purecopy "*Python*"))
 \f
 ;;;; Font lock
 
 (defvar python-font-lock-keywords
   `(,(rx symbol-start
-        ;; From v 2.5 reference, § keywords.
+        ;; From v 2.7 reference, § keywords.
         ;; def and class dealt with separately below
         (or "and" "as" "assert" "break" "continue" "del" "elif" "else"
             "except" "exec" "finally" "for" "from" "global" "if"
              ;; Not real keywords, but close enough to be fontified as such
              "self" "True" "False")
         symbol-end)
-    (,(rx symbol-start "None" symbol-end)      ; see § Keywords in 2.5 manual
+    (,(rx symbol-start "None" symbol-end)      ; see § Keywords in 2.7 manual
      . font-lock-constant-face)
     ;; Definitions
     (,(rx symbol-start (group "class") (1+ space) (group (1+ (or word ?_))))
     ;; Top-level assignments are worth highlighting.
     (,(rx line-start (group (1+ (or word ?_))) (0+ space) "=")
      (1 font-lock-variable-name-face))
-    (,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_)))) ; decorators
+    ;; Decorators.
+    (,(rx line-start (* (any " \t")) (group "@" (1+ (or word ?_))
+                                           (0+ "." (1+ (or word ?_)))))
      (1 font-lock-type-face))
     ;; Built-ins.  (The next three blocks are from
-    ;; `__builtin__.__dict__.keys()' in Python 2.5.1.)  These patterns
+    ;; `__builtin__.__dict__.keys()' in Python 2.7)  These patterns
     ;; are debateable, but they at least help to spot possible
     ;; shadowing of builtins.
     (,(rx symbol-start (or
          "SystemExit" "TabError" "TypeError" "UnboundLocalError"
          "UnicodeDecodeError" "UnicodeEncodeError" "UnicodeError"
          "UnicodeTranslateError" "UnicodeWarning" "UserWarning"
-         "ValueError" "Warning" "ZeroDivisionError") symbol-end)
+         "ValueError" "Warning" "ZeroDivisionError"
+         ;; Python 2.7
+         "BufferError" "BytesWarning" "WindowsError") symbol-end)
      . font-lock-type-face)
     (,(rx (or line-start (not (any ". \t"))) (* (any " \t")) symbol-start
          (group (or
          "range" "raw_input" "reduce" "reload" "repr" "reversed"
          "round" "set" "setattr" "slice" "sorted" "staticmethod"
          "str" "sum" "super" "tuple" "type" "unichr" "unicode" "vars"
-         "xrange" "zip")) symbol-end)
+         "xrange" "zip"
+         ;; Python 2.7.
+         "bin" "bytearray" "bytes" "format" "memoryview" "next" "print"
+         )) symbol-end)
      (1 font-lock-builtin-face))
     (,(rx symbol-start (or
          ;; other built-ins
          "True" "False" "None" "Ellipsis"
-         "_" "__debug__" "__doc__" "__import__" "__name__") symbol-end)
+         "_" "__debug__" "__doc__" "__import__" "__name__" "__package__")
+          symbol-end)
      . font-lock-builtin-face)))
 
-(defconst python-font-lock-syntactic-keywords
+(defconst python-syntax-propertize-function
   ;; Make outer chars of matching triple-quote sequences into generic
   ;; string delimiters.  Fixme: Is there a better way?
   ;; First avoid a sequence preceded by an odd number of backslashes.
-  `((,(rx (not (any ?\\))
-         ?\\ (* (and ?\\ ?\\))
-         (group (syntax string-quote))
-         (backref 1)
-         (group (backref 1)))
-     (2 ,(string-to-syntax "\"")))     ; dummy
-    (,(rx (group (optional (any "uUrR"))) ; prefix gets syntax property
-         (optional (any "rR"))           ; possible second prefix
-         (group (syntax string-quote))   ; maybe gets property
-         (backref 2)                     ; per first quote
-         (group (backref 2)))            ; maybe gets property
-     (1 (python-quote-syntax 1))
-     (2 (python-quote-syntax 2))
-     (3 (python-quote-syntax 3)))
-    ;; This doesn't really help.
-;;;     (,(rx (and ?\\ (group ?\n))) (1 " "))
-    ))
-
-(defun python-quote-syntax (n)
+  (syntax-propertize-rules
+   (;; ¡Backrefs don't work in syntax-propertize-rules!
+    (concat "\\(?:\\([RUru]\\)[Rr]?\\|^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix.
+              "\\(?:\\('\\)'\\('\\)\\|\\(?2:\"\\)\"\\(?3:\"\\)\\)")
+    (3 (ignore (python-quote-syntax))))
+   ;; This doesn't really help.
+   ;;((rx (and ?\\ (group ?\n))) (1 " "))
+   ))
+
+(defun python-quote-syntax ()
   "Put `syntax-table' property correctly on triple quote.
 Used for syntactic keywords.  N is the match number (1, 2 or 3)."
   ;; Given a triple quote, we have to check the context to know
@@ -198,28 +197,25 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
   ;; x '"""' x """ \"""" x
   (save-excursion
     (goto-char (match-beginning 0))
-    (cond
-     ;; Consider property for the last char if in a fenced string.
-     ((= n 3)
-      (let* ((font-lock-syntactic-keywords nil)
-            (syntax (syntax-ppss)))
-       (when (eq t (nth 3 syntax))     ; after unclosed fence
-         (goto-char (nth 8 syntax))    ; fence position
-         (skip-chars-forward "uUrR")   ; skip any prefix
-         ;; Is it a matching sequence?
-         (if (eq (char-after) (char-after (match-beginning 2)))
-             (eval-when-compile (string-to-syntax "|"))))))
-     ;; Consider property for initial char, accounting for prefixes.
-     ((or (and (= n 2)                 ; leading quote (not prefix)
-              (= (match-beginning 1) (match-end 1))) ; prefix is null
-         (and (= n 1)                  ; prefix
-              (/= (match-beginning 1) (match-end 1)))) ; non-empty
-      (let ((font-lock-syntactic-keywords nil))
-       (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
-         (eval-when-compile (string-to-syntax "|")))))
-     ;; Otherwise (we're in a non-matching string) the property is
-     ;; nil, which is OK.
-     )))
+    (let ((syntax (save-match-data (syntax-ppss))))
+      (cond
+       ((eq t (nth 3 syntax))           ; after unclosed fence
+        ;; Consider property for the last char if in a fenced string.
+        (goto-char (nth 8 syntax))     ; fence position
+        (skip-chars-forward "uUrR")    ; skip any prefix
+        ;; Is it a matching sequence?
+        (if (eq (char-after) (char-after (match-beginning 2)))
+            (put-text-property (match-beginning 3) (match-end 3)
+                               'syntax-table (string-to-syntax "|"))))
+       ((match-end 1)
+        ;; Consider property for initial char, accounting for prefixes.
+        (put-text-property (match-beginning 1) (match-end 1)
+                           'syntax-table (string-to-syntax "|")))
+       (t
+        ;; Consider property for initial char, accounting for prefixes.
+        (put-text-property (match-beginning 2) (match-end 2)
+                           'syntax-table (string-to-syntax "|"))))
+      )))
 
 ;; This isn't currently in `font-lock-defaults' as probably not worth
 ;; it -- we basically only mess with a few normally-symbol characters.
@@ -267,7 +263,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
     (define-key map "\C-c\C-z" 'python-switch-to-python)
     (define-key map "\C-c\C-m" 'python-load-file)
     (define-key map "\C-c\C-l" 'python-load-file) ; a la cmuscheme
-    (substitute-key-definition 'complete-symbol 'symbol-complete
+    (substitute-key-definition 'complete-symbol 'completion-at-point
                               map global-map)
     (define-key map "\C-c\C-i" 'python-find-imports)
     (define-key map "\C-c\C-t" 'python-expand-template)
@@ -296,9 +292,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
        ("Templates..."
         :help "Expand templates for compound statements"
         :filter (lambda (&rest junk)
-                  (mapcar (lambda (elt)
-                            (vector (car elt) (cdr elt) t))
-                          python-skeletons))) ; defined later
+                   (abbrev-table-menu python-mode-abbrev-table)))
        "-"
        ["Start interpreter" python-shell
         :help "Run `inferior' Python in separate buffer"]
@@ -320,7 +314,7 @@ Used for syntactic keywords.  N is the match number (1, 2 or 3)."
        "-"
        ["Help on symbol" python-describe-symbol
         :help "Use pydoc on symbol at point"]
-       ["Complete symbol" symbol-complete
+       ["Complete symbol" completion-at-point
         :help "Complete (qualified) symbol before point"]
        ["Find function" python-find-function
         :help "Try to find source definition of function at point"]
@@ -411,7 +405,7 @@ comments and strings, or that point is within brackets/parens."
                    (error nil))))))))
 
 (defun python-comment-line-p ()
-  "Return non-nil iff current line has only a comment."
+  "Return non-nil if and only if current line has only a comment."
   (save-excursion
     (end-of-line)
     (when (eq 'comment (syntax-ppss-context (syntax-ppss)))
@@ -419,7 +413,7 @@ comments and strings, or that point is within brackets/parens."
       (looking-at (rx (or (syntax comment-start) line-end))))))
 
 (defun python-blank-line-p ()
-  "Return non-nil iff current line is blank."
+  "Return non-nil if and only if current line is blank."
   (save-excursion
     (beginning-of-line)
     (looking-at "\\s-*$")))
@@ -545,27 +539,68 @@ mode buffer is visited during an Emacs session.  After that, use
 
 (defcustom python-pdbtrack-do-tracking-p t
   "*Controls whether the pdbtrack feature is enabled or not.
+
 When non-nil, pdbtrack is enabled in all comint-based buffers,
-e.g. shell buffers and the *Python* buffer.  When using pdb to debug a
-Python program, pdbtrack notices the pdb prompt and displays the
-source file and line that the program is stopped at, much the same way
-as gud-mode does for debugging C programs with gdb."
+e.g. shell interaction buffers and the *Python* buffer.
+
+When using pdb to debug a Python program, pdbtrack notices the
+pdb prompt and presents the line in the source file where the
+program is stopped in a pop-up buffer.  It's similar to what
+gud-mode does for debugging C programs with gdb, but without
+having to restart the program."
   :type 'boolean
   :group 'python)
 (make-variable-buffer-local 'python-pdbtrack-do-tracking-p)
 
+(defcustom python-pdbtrack-minor-mode-string " PDB"
+  "*Minor-mode sign to be displayed when pdbtrack is active."
+  :type 'string
+  :group 'python)
+
+;; Add a designator to the minor mode strings
+(or (assq 'python-pdbtrack-is-tracking-p minor-mode-alist)
+    (push '(python-pdbtrack-is-tracking-p python-pdbtrack-minor-mode-string)
+         minor-mode-alist))
+
 ;; Bind python-file-queue before installing the kill-emacs-hook.
 (defvar python-file-queue nil
   "Queue of Python temp files awaiting execution.
 Currently-active file is at the head of the list.")
 
+(defcustom python-shell-prompt-alist
+  '(("ipython" . "^In \\[[0-9]+\\]: *")
+    (t . "^>>> "))
+  "Alist of Python input prompts.
+Each element has the form (PROGRAM . REGEXP), where PROGRAM is
+the value of `python-python-command' for the python process and
+REGEXP is a regular expression matching the Python prompt.
+PROGRAM can also be t, which specifies the default when no other
+element matches `python-python-command'."
+  :type 'string
+  :group 'python
+  :version "24.1")
+
+(defcustom python-shell-continuation-prompt-alist
+  '(("ipython" . "^   [.][.][.]+: *")
+    (t . "^[.][.][.] "))
+  "Alist of Python continued-line prompts.
+Each element has the form (PROGRAM . REGEXP), where PROGRAM is
+the value of `python-python-command' for the python process and
+REGEXP is a regular expression matching the Python prompt for
+continued lines.
+PROGRAM can also be t, which specifies the default when no other
+element matches `python-python-command'."
+  :type 'string
+  :group 'python
+  :version "24.1")
+
 (defvar python-pdbtrack-is-tracking-p nil)
 
 (defconst python-pdbtrack-stack-entry-regexp
-  "> \\([^(]+\\)(\\([0-9]+\\))[?a-zA-Z0-9_]+()"
+  "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
   "Regular expression pdbtrack uses to find a stack trace entry.")
 
-(defconst python-pdbtrack-input-prompt "\n[(<]?pdb[>)]? "
+(defconst python-pdbtrack-input-prompt "\n[(<]*[Pp]db[>)]+ "
   "Regular expression pdbtrack uses to recognize a pdb prompt.")
 
 (defconst python-pdbtrack-track-range 10000
@@ -735,7 +770,7 @@ Set `python-indent' locally to the value guessed."
   '(("else" "if" "elif" "while" "for" "try" "except")
     ("elif" "if" "elif")
     ("except" "try" "except")
-    ("finally" "try"))
+    ("finally" "else" "try" "except"))
   "Alist of keyword matches.
 The car of an element is a keyword introducing a statement which
 can close a block opened by a keyword in the cdr.")
@@ -965,9 +1000,11 @@ Accounts for continuation lines, multi-line strings, and
 multi-line bracketed expressions."
   (beginning-of-line)
   (python-beginning-of-string)
-  (let ((point (point)))
+  (let (point)
     (while (and (python-continuation-line-p)
-               (> point (setq point (point))))
+               (if point
+                   (< (point) point)
+                 t))
       (beginning-of-line)
       (if (python-backslash-continuation-line-p)
          (progn
@@ -975,14 +1012,15 @@ multi-line bracketed expressions."
            (while (python-backslash-continuation-line-p)
              (forward-line -1)))
        (python-beginning-of-string)
-       (python-skip-out))))
+       (python-skip-out))
+      (setq point (point))))
   (back-to-indentation))
 
 (defun python-skip-out (&optional forward syntax)
   "Skip out of any nested brackets.
 Skip forward if FORWARD is non-nil, else backward.
 If SYNTAX is non-nil it is the state returned by `syntax-ppss' at point.
-Return non-nil iff skipping was done."
+Return non-nil if and only if skipping was done."
   (let ((depth (syntax-ppss-depth (or syntax (syntax-ppss))))
        (forward (if forward -1 1)))
     (unless (zerop depth)
@@ -1288,13 +1326,9 @@ See `python-check-command' for the default."
 \f
 ;;;; Inferior mode stuff (following cmuscheme).
 
-;; Fixme: Make sure we can work with IPython.
-
 (defcustom python-python-command "python"
   "Shell command to run Python interpreter.
-Any arguments can't contain whitespace.
-Note that IPython may not work properly; it must at least be used
-with the `-cl' flag, i.e. use `ipython -cl'."
+Any arguments can't contain whitespace."
   :group 'python
   :type 'string)
 
@@ -1372,6 +1406,23 @@ local value.")
 ;; Autoloaded.
 (declare-function compilation-shell-minor-mode "compile" (&optional arg))
 
+(defvar python--prompt-regexp nil)
+
+(defun python--set-prompt-regexp ()
+  (let ((prompt  (cdr-safe (or (assoc python-python-command
+                                     python-shell-prompt-alist)
+                              (assq t python-shell-prompt-alist))))
+       (cprompt (cdr-safe (or (assoc python-python-command
+                                     python-shell-continuation-prompt-alist)
+                              (assq t python-shell-continuation-prompt-alist)))))
+    (set (make-local-variable 'comint-prompt-regexp)
+        (concat "\\("
+                (mapconcat 'identity
+                           (delq nil (list prompt cprompt "^([Pp]db) "))
+                           "\\|")
+                "\\)"))
+    (set (make-local-variable 'python--prompt-regexp) prompt)))
+
 ;; Fixme: This should inherit some stuff from `python-mode', but I'm
 ;; not sure how much: at least some keybindings, like C-c C-f;
 ;; syntax?; font-locking, e.g. for triple-quoted strings?
@@ -1394,14 +1445,12 @@ For running multiple processes in multiple buffers, see `run-python' and
 
 \\{inferior-python-mode-map}"
   :group 'python
+  (require 'ansi-color) ; for ipython
   (setq mode-line-process '(":%s"))
   (set (make-local-variable 'comint-input-filter) 'python-input-filter)
   (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter
            nil t)
-  ;; Still required by `comint-redirect-send-command', for instance
-  ;; (and we need to match things like `>>> ... >>> '):
-  (set (make-local-variable 'comint-prompt-regexp)
-       (rx line-start (1+ (and (or (repeat 3 (any ">.")) "(Pdb)") " "))))
+  (python--set-prompt-regexp)
   (set (make-local-variable 'compilation-error-regexp-alist)
        python-compilation-regexp-alist)
   (compilation-shell-minor-mode 1))
@@ -1498,12 +1547,12 @@ Don't save anything for STR matching `inferior-python-filter-regexp'."
                                     cmd)))
     (unless (shell-command-to-string cmd)
       (error "Can't run Python command `%s'" cmd))
-    (let* ((res (shell-command-to-string (concat cmd " --version"))))
-      (string-match "Python \\([0-9]\\)\\.\\([0-9]\\)" res)
-      (unless (and (equal "2" (match-string 1 res))
-                  (match-beginning 2)
-                  (>= (string-to-number (match-string 2 res)) 2))
-       (error "Only Python versions >= 2.2 and < 3.0 supported")))
+    (let* ((res (shell-command-to-string
+                 (concat cmd
+                         " -c \"from sys import version_info;\
+print version_info >= (2, 2) and version_info < (3, 0)\""))))
+      (unless (string-match "True" res)
+       (error "Only Python versions >= 2.2 and < 3.0 are supported")))
     (setq python-version-checked t)))
 
 ;;;###autoload
@@ -1526,6 +1575,7 @@ buffer for a list of commands.)"
   (interactive (if current-prefix-arg
                   (list (read-string "Run Python: " python-command) nil t)
                 (list python-command)))
+  (require 'ansi-color) ; for ipython
   (unless cmd (setq cmd python-command))
   (python-check-version cmd)
   (setq python-command cmd)
@@ -1534,15 +1584,24 @@ buffer for a list of commands.)"
   ;; invoked.  Would support multiple processes better.
   (when (or new (not (comint-check-proc python-buffer)))
     (with-current-buffer
-       (let* ((cmdlist (append (python-args-to-list cmd) '("-i")))
+       (let* ((cmdlist
+               (append (python-args-to-list cmd)
+                        ;; It's easy for the user to cause the process to be
+                       ;; started without realizing it (e.g. to perform
+                       ;; completion); for this reason loading files from the
+                       ;; current directory is a security risk.  See
+                       ;; http://article.gmane.org/gmane.emacs.devel/103569
+                       '("-i" "-c" "import sys; sys.path.remove('')")))
               (path (getenv "PYTHONPATH"))
               (process-environment     ; to import emacs.py
                (cons (concat "PYTHONPATH="
                              (if path (concat path path-separator))
                              data-directory)
                      process-environment))
-              ;; Suppress use of pager for help output:
-              (process-connection-type nil))
+               ;; If we use a pipe, unicode characters are not printed
+               ;; correctly (Bug#5794) and IPython does not work at
+               ;; all (Bug#5390).
+              (process-connection-type t))
          (apply 'make-comint-in-buffer "Python"
                 (generate-new-buffer "*Python*")
                 (car cmdlist) nil (cdr cmdlist)))
@@ -1598,7 +1657,12 @@ buffer for a list of commands.)"
   ;; non-ASCII.
   (interactive "r")
   (let* ((f (make-temp-file "py"))
-        (command (format "emacs.eexecfile(%S)" f))
+        (command
+          ;; IPython puts the FakeModule module into __main__ so
+          ;; emacs.eexecfile becomes useless.
+          (if (string-match "^ipython" python-command)
+              (format "execfile %S" f)
+            (format "emacs.eexecfile(%S)" f)))
         (orig-start (copy-marker start)))
     (when (save-excursion
            (goto-char start)
@@ -1767,9 +1831,10 @@ will."
     (with-output-to-temp-buffer (help-buffer)
       (with-current-buffer standard-output
        ;; Fixme: Is this actually useful?
-       (help-setup-xref (list 'python-describe-symbol symbol) (interactive-p))
+       (help-setup-xref (list 'python-describe-symbol symbol)
+                        (called-interactively-p 'interactive))
        (set (make-local-variable 'comint-redirect-subvert-readonly) t)
-       (print-help-return-message))))
+       (help-print-return-message))))
   (comint-redirect-send-command-to-process (format "emacs.ehelp(%S, %s)"
                                                   symbol python-imports)
    "*Help*" (python-proc) nil nil))
@@ -1792,13 +1857,14 @@ This is a no-op if `python-check-comint-prompt' returns nil."
          (kill-local-variable 'python-preoutput-result))))))
 
 (defun python-check-comint-prompt (&optional proc)
-  "Return non-nil iff there's a normal prompt in the inferior buffer.
-If there isn't, it's probably not appropriate to send input to return
-Eldoc information etc.  If PROC is non-nil, check the buffer for that
-process."
+  "Return non-nil if and only if there's a normal prompt in the inferior buffer.
+If there isn't, it's probably not appropriate to send input to return Eldoc
+information etc.  If PROC is non-nil, check the buffer for that process."
   (with-current-buffer (process-buffer (or proc (python-proc)))
     (save-excursion
-      (save-match-data (re-search-backward ">>> \\=" nil t)))))
+      (save-match-data
+       (re-search-backward (concat python--prompt-regexp " *\\=")
+                           nil t)))))
 
 ;; Fixme:  Is there anything reasonable we can do with random methods?
 ;; (Currently only works with functions.)
@@ -1991,9 +2057,10 @@ COUNT defaults to `python-indent'.  If region isn't active, just shift
 current line.  The region shifted includes the lines in which START and
 END lie.  It is an error if any lines in the region are indented less than
 COUNT columns."
-  (interactive (if mark-active
-                  (list (region-beginning) (region-end) current-prefix-arg)
-                (list (point) (point) current-prefix-arg)))
+  (interactive
+   (if mark-active
+       (list (region-beginning) (region-end) current-prefix-arg)
+     (list (line-beginning-position) (line-end-position) current-prefix-arg)))
   (if count
       (setq count (prefix-numeric-value count))
     (setq count python-indent))
@@ -2014,9 +2081,10 @@ COUNT columns."
 COUNT defaults to `python-indent'.  If region isn't active, just shift
 current line.  The region shifted includes the lines in which START and
 END lie."
-  (interactive (if mark-active
-                  (list (region-beginning) (region-end) current-prefix-arg)
-                (list (point) (point) current-prefix-arg)))
+  (interactive
+   (if mark-active
+       (list (region-beginning) (region-end) current-prefix-arg)
+     (list (line-beginning-position) (line-end-position) current-prefix-arg)))
   (if count
       (setq count (prefix-numeric-value count))
     (setq count python-indent))
@@ -2127,20 +2195,21 @@ Uses `python-beginning-of-block', `python-end-of-block'."
   "Return a list of completions of the string SYMBOL from Python process.
 The list is sorted.
 Uses `python-imports' to load modules against which to complete."
-  (when symbol
+  (when (stringp symbol)
     (let ((completions
           (condition-case ()
               (car (read-from-string
                     (python-send-receive
-                     (format "emacs.complete(%S,%s)" symbol python-imports))))
+                     (format "emacs.complete(%S,%s)"
+                             (substring-no-properties symbol)
+                             python-imports))))
             (error nil))))
       (sort
        ;; We can get duplicates from the above -- don't know why.
        (delete-dups completions)
        #'string<))))
 
-(defun python-partial-symbol ()
-  "Return the partial symbol before point (for completion)."
+(defun python-completion-at-point ()
   (let ((end (point))
        (start (save-excursion
                 (and (re-search-backward
@@ -2148,7 +2217,9 @@ Uses `python-imports' to load modules against which to complete."
                           (group (1+ (regexp "[[:alnum:]._]"))) point)
                       nil t)
                      (match-beginning 1)))))
-    (if start (buffer-substring-no-properties start end))))
+    (when start
+      (list start end
+            (completion-table-dynamic 'python-symbol-completions)))))
 \f
 ;;;; FFAP support
 
@@ -2184,7 +2255,8 @@ Interactively, prompt for name."
     (unless file (error "Don't know where `%s' is defined" name))
     (pop-to-buffer (find-file-noselect file))
     (when (integerp line)
-      (goto-line line))))
+      (goto-char (point-min))
+      (forward-line (1- line)))))
 \f
 ;;;; Skeletons
 
@@ -2195,37 +2267,30 @@ the if condition."
   :type 'boolean
   :group 'python)
 
-(defvar python-skeletons nil
-  "Alist of named skeletons for Python mode.
-Elements are of the form (NAME . EXPANDER-FUNCTION).")
-
 (define-abbrev-table 'python-mode-abbrev-table ()
-  "Abbrev table for Python mode.
-The default contents correspond to the elements of `python-skeletons'."
-  ;; Allow / in abbrevs.
-  :regexp "\\<\\([[:word:]/]+\\)\\W*")
+  "Abbrev table for Python mode."
+  :case-fixed t
+  ;; Allow / inside abbrevs.
+  :regexp "\\(?:^\\|[^/]\\)\\<\\([[:word:]/]+\\)\\W*"
+  ;; Only expand in code.
+  :enable-function (lambda () (not (python-in-string/comment))))
 
 (eval-when-compile
-  ;; Define a user-level skeleton and add it to `python-skeletons' and
-  ;; the abbrev table.
+  ;; Define a user-level skeleton and add it to the abbrev table.
 (defmacro def-python-skeleton (name &rest elements)
+  (declare (indent 2))
   (let* ((name (symbol-name name))
         (function (intern (concat "python-insert-" name))))
     `(progn
-       (add-to-list 'python-skeletons ',(cons name function))
        ;; Usual technique for inserting a skeleton, but expand
        ;; to the original abbrev instead if in a comment or string.
-       (define-abbrev python-mode-abbrev-table ,name ""
-        ;; Quote this to give a readable abbrev table.
-        '(lambda ()
-           (if (python-in-string/comment)
-               (insert ,name)
-             (,function)))
-        nil t)                         ; system abbrev
+       (when python-use-skeletons
+         (define-abbrev python-mode-abbrev-table ,name ""
+           ',function
+           nil t))                      ; system abbrev
        (define-skeleton ,function
         ,(format "Insert Python \"%s\" template." name)
         ,@elements)))))
-(put 'def-python-skeleton 'lisp-indent-function 2)
 
 ;; From `skeleton-further-elements' set below:
 ;;  `<': outdent a level;
@@ -2313,13 +2378,14 @@ Interactively, prompt for the name with completion."
   (interactive
    (list (completing-read (format "Template to expand (default %s): "
                                  python-default-template)
-                         python-skeletons nil t)))
+                         python-mode-abbrev-table nil t nil nil
+                          python-default-template)))
   (if (equal "" name)
       (setq name python-default-template)
     (setq python-default-template name))
-  (let ((func (cdr (assoc name python-skeletons))))
-    (if func
-       (funcall func)
+  (let ((sym (abbrev-symbol name python-mode-abbrev-table)))
+    (if sym
+        (abbrev-insert sym)
       (error "Undefined template: %s" name))))
 \f
 ;;;; Bicycle Repair Man support
@@ -2375,26 +2441,14 @@ without confirmation."
 \f
 ;;;; Modes.
 
+;; pdb tracking is alert once this file is loaded, but takes no action if
+;; `python-pdbtrack-do-tracking-p' is nil.
+(add-hook 'comint-output-filter-functions 'python-pdbtrack-track-stack-file)
+
 (defvar outline-heading-end-regexp)
 (defvar eldoc-documentation-function)
 (defvar python-mode-running)            ;Dynamically scoped var.
 
-;; Stuff to allow expanding abbrevs with non-word constituents.
-(defun python-abbrev-pc-hook ()
-  "Reset the syntax table after possibly expanding abbrevs."
-  (remove-hook 'post-command-hook 'python-abbrev-pc-hook t)
-  (set-syntax-table python-mode-syntax-table))
-
-(defvar python-abbrev-syntax-table
-  (copy-syntax-table python-mode-syntax-table)
-  "Syntax table used when expanding abbrevs.")
-
-(defun python-pea-hook ()
-  "Set the syntax table before possibly expanding abbrevs."
-  (set-syntax-table python-abbrev-syntax-table)
-  (add-hook 'post-command-hook 'python-abbrev-pc-hook nil t))
-(modify-syntax-entry ?/ "w" python-abbrev-syntax-table)
-
 ;;;###autoload
 (define-derived-mode python-mode fundamental-mode "Python"
   "Major mode for editing Python files.
@@ -2434,12 +2488,12 @@ with skeleton expansions for compound statement templates.
   :group 'python
   (set (make-local-variable 'font-lock-defaults)
        '(python-font-lock-keywords nil nil nil nil
-                                  (font-lock-syntactic-keywords
-                                   . python-font-lock-syntactic-keywords)
-                                  ;; This probably isn't worth it.
-                                  ;; (font-lock-syntactic-face-function
-                                  ;;  . python-font-lock-syntactic-face-function)
-                                  ))
+         ;; This probably isn't worth it.
+         ;; (font-lock-syntactic-face-function
+         ;;  . python-font-lock-syntactic-face-function)
+         ))
+  (set (make-local-variable 'syntax-propertize-function)
+       python-syntax-propertize-function)
   (set (make-local-variable 'parse-sexp-lookup-properties) t)
   (set (make-local-variable 'parse-sexp-ignore-comments) t)
   (set (make-local-variable 'comment-start) "# ")
@@ -2468,10 +2522,8 @@ with skeleton expansions for compound statement templates.
   (add-hook 'eldoc-mode-hook
            (lambda () (run-python nil t)) ; need it running
            nil t)
-  (set (make-local-variable 'symbol-completion-symbol-function)
-       'python-partial-symbol)
-  (set (make-local-variable 'symbol-completion-completions-function)
-       'python-symbol-completions)
+  (add-hook 'completion-at-point-functions
+            'python-completion-at-point nil 'local)
   ;; Fixme: should be in hideshow.  This seems to be of limited use
   ;; since it isn't (can't be) indentation-based.  Also hide-level
   ;; doesn't seem to work properly.
@@ -2485,11 +2537,6 @@ with skeleton expansions for compound statement templates.
        '((< '(backward-delete-char-untabify (min python-indent
                                                 (current-column))))
         (^ '(- (1+ (current-indentation))))))
-  (add-hook 'pre-abbrev-expand-hook 'python-pea-hook nil t)
-  (if (featurep 'hippie-exp)
-      (set (make-local-variable 'hippie-expand-try-functions-list)
-          (cons 'symbol-completion-try-complete
-                hippie-expand-try-functions-list)))
   ;; Python defines TABs as being 8-char wide.
   (set (make-local-variable 'tab-width) 8)
   (unless font-lock-mode (font-lock-mode 1))
@@ -2529,188 +2576,32 @@ Runs `jython-mode-hook' after `python-mode-hook'."
 
 ;; pdbtrack features
 
-(defsubst python-point (position)
-  "Returns the value of point at certain commonly referenced POSITIONs.
-POSITION can be one of the following symbols:
-
-  bol  -- beginning of line
-  eol  -- end of line
-  bod  -- beginning of def or class
-  eod  -- end of def or class
-  bob  -- beginning of buffer
-  eob  -- end of buffer
-  boi  -- back to indentation
-  bos  -- beginning of statement
-
-This function does not modify point or mark."
-  (let ((here (point)))
-    (cond
-     ((eq position 'bol) (beginning-of-line))
-     ((eq position 'eol) (end-of-line))
-     ((eq position 'bod) (python-beginning-of-def-or-class))
-     ((eq position 'eod) (python-end-of-def-or-class))
-     ;; Kind of funny, I know, but useful for python-up-exception.
-     ((eq position 'bob) (goto-char (point-min)))
-     ((eq position 'eob) (goto-char (point-max)))
-     ((eq position 'boi) (back-to-indentation))
-     ((eq position 'bos) (python-goto-initial-line))
-     (t (error "Unknown buffer position requested: %s" position)))
-    (prog1
-       (point)
-      (goto-char here))))
-
-(defun python-end-of-def-or-class (&optional class count)
-  "Move point beyond end of `def' or `class' body.
-
-By default, looks for an appropriate `def'.  If you supply a prefix
-arg, looks for a `class' instead.  The docs below assume the `def'
-case; just substitute `class' for `def' for the other case.
-Programmatically, if CLASS is `either', then moves to either `class'
-or `def'.
-
-When second optional argument is given programmatically, move to the
-COUNTth end of `def'.
-
-If point is in a `def' statement already, this is the `def' we use.
-
-Else, if the `def' found by `\\[python-beginning-of-def-or-class]'
-contains the statement you started on, that's the `def' we use.
-
-Otherwise, we search forward for the closest following `def', and use that.
-
-If a `def' can be found by these rules, point is moved to the start of
-the line immediately following the `def' block, and the position of the
-start of the `def' is returned.
-
-Else point is moved to the end of the buffer, and nil is returned.
-
-Note that doing this command repeatedly will take you closer to the
-end of the buffer each time.
-
-To mark the current `def', see `\\[python-mark-def-or-class]'."
-  (interactive "P")                    ; raw prefix arg
-  (if (and count (/= count 1))
-      (python-beginning-of-def-or-class (- 1 count)))
-  (let ((start (progn (python-goto-initial-line) (point)))
-       (which (cond ((eq class 'either) "\\(class\\|def\\)")
-                    (class "class")
-                    (t "def")))
-       (state 'not-found))
-    ;; move point to start of appropriate def/class
-    (if (looking-at (concat "[ \t]*" which "\\>")) ; already on one
-       (setq state 'at-beginning)
-      ;; else see if python-beginning-of-def-or-class hits container
-      (if (and (python-beginning-of-def-or-class class)
-              (progn (python-goto-beyond-block)
-                     (> (point) start)))
-         (setq state 'at-end)
-       ;; else search forward
-       (goto-char start)
-       (if (re-search-forward (concat "^[ \t]*" which "\\>") nil 'move)
-           (progn (setq state 'at-beginning)
-                  (beginning-of-line)))))
-    (cond
-     ((eq state 'at-beginning) (python-goto-beyond-block) t)
-     ((eq state 'at-end) t)
-     ((eq state 'not-found) nil)
-     (t (error "Internal error in `python-end-of-def-or-class'")))))
-
-(defun python-beginning-of-def-or-class (&optional class count)
-  "Move point to start of `def' or `class'.
-
-Searches back for the closest preceding `def'.  If you supply a prefix
-arg, looks for a `class' instead.  The docs below assume the `def'
-case; just substitute `class' for `def' for the other case.
-Programmatically, if CLASS is `either', then moves to either `class'
-or `def'.
-
-When second optional argument is given programmatically, move to the
-COUNTth start of `def'.
-
-If point is in a `def' statement already, and after the `d', simply
-moves point to the start of the statement.
-
-Otherwise (i.e. when point is not in a `def' statement, or at or
-before the `d' of a `def' statement), searches for the closest
-preceding `def' statement, and leaves point at its start.  If no such
-statement can be found, leaves point at the start of the buffer.
-
-Returns t iff a `def' statement is found by these rules.
-
-Note that doing this command repeatedly will take you closer to the
-start of the buffer each time.
-
-To mark the current `def', see `\\[python-mark-def-or-class]'."
-  (interactive "P")                    ; raw prefix arg
-  (setq count (or count 1))
-  (let ((at-or-before-p (<= (current-column) (current-indentation)))
-       (start-of-line (goto-char (python-point 'bol)))
-       (start-of-stmt (goto-char (python-point 'bos)))
-       (start-re (cond ((eq class 'either) "^[ \t]*\\(class\\|def\\)\\>")
-                       (class "^[ \t]*class\\>")
-                       (t "^[ \t]*def\\>"))))
-    ;; searching backward
-    (if (and (< 0 count)
-            (or (/= start-of-stmt start-of-line)
-                (not at-or-before-p)))
-       (end-of-line))
-    ;; search forward
-    (if (and (> 0 count)
-            (zerop (current-column))
-            (looking-at start-re))
-       (end-of-line))
-    (if (re-search-backward start-re nil 'move count)
-       (goto-char (match-beginning 0)))))
-
-(defun python-goto-initial-line ()
-  "Go to the initial line of the current statement.
-Usually this is the line we're on, but if we're on the 2nd or
-following lines of a continuation block, we need to go up to the first
-line of the block."
-  ;; Tricky: We want to avoid quadratic-time behavior for long
-  ;; continued blocks, whether of the backslash or open-bracket
-  ;; varieties, or a mix of the two.  The following manages to do that
-  ;; in the usual cases.
-  ;;
-  ;; Also, if we're sitting inside a triple quoted string, this will
-  ;; drop us at the line that begins the string.
-  (let (open-bracket-pos)
-    (while (python-continuation-line-p)
-      (beginning-of-line)
-      (if (python-backslash-continuation-line-p)
-         (while (python-backslash-continuation-line-p)
-           (forward-line -1))
-       ;; else zip out of nested brackets/braces/parens
-       (while (setq open-bracket-pos (python-nesting-level))
-         (goto-char open-bracket-pos)))))
-  (beginning-of-line))
-
 (defun python-comint-output-filter-function (string)
   "Watch output for Python prompt and exec next file waiting in queue.
 This function is appropriate for `comint-output-filter-functions'."
   ;; TBD: this should probably use split-string
-  (when (and (or (string-equal string ">>> ")
-                (and (>= (length string) 5)
-                     (string-equal (substring string -5) "\n>>> ")))
+  (when (and (string-match python--prompt-regexp string)
             python-file-queue)
-    (python-safe (delete-file (car python-file-queue)))
+    (condition-case nil
+        (delete-file (car python-file-queue))
+      (error nil))
     (setq python-file-queue (cdr python-file-queue))
     (if python-file-queue
        (let ((pyproc (get-buffer-process (current-buffer))))
          (python-execute-file pyproc (car python-file-queue))))))
 
 (defun python-pdbtrack-overlay-arrow (activation)
-  "Activate or de arrow at beginning-of-line in current buffer."
-  ;; This was derived/simplified from edebug-overlay-arrow
-  (cond (activation
-        (setq overlay-arrow-position (make-marker))
-        (setq overlay-arrow-string "=>")
-        (set-marker overlay-arrow-position
-                    (python-point 'bol) (current-buffer))
-        (setq python-pdbtrack-is-tracking-p t))
-       (python-pdbtrack-is-tracking-p
-        (setq overlay-arrow-position nil)
-        (setq python-pdbtrack-is-tracking-p nil))))
+  "Activate or deactivate arrow at beginning-of-line in current buffer."
+  (if activation
+      (progn
+        (setq overlay-arrow-position (make-marker)
+              overlay-arrow-string "=>"
+              python-pdbtrack-is-tracking-p t)
+        (set-marker overlay-arrow-position
+                    (line-beginning-position)
+                    (current-buffer)))
+    (setq overlay-arrow-position nil
+          python-pdbtrack-is-tracking-p nil)))
 
 (defun python-pdbtrack-track-stack-file (text)
   "Show the file indicated by the pdb stack entry line, in a separate window.
@@ -2718,49 +2609,130 @@ This function is appropriate for `comint-output-filter-functions'."
 Activity is disabled if the buffer-local variable
 `python-pdbtrack-do-tracking-p' is nil.
 
-We depend on the pdb input prompt matching `python-pdbtrack-input-prompt'
-at the beginning of the line."
+We depend on the pdb input prompt being a match for
+`python-pdbtrack-input-prompt'.
+
+If the traceback target file path is invalid, we look for the
+most recently visited python-mode buffer which either has the
+name of the current function or class, or which defines the
+function or class.  This is to provide for scripts not in the
+local filesytem (e.g., Zope's 'Script \(Python)', but it's not
+Zope specific).  If you put a copy of the script in a buffer
+named for the script and activate python-mode, then pdbtrack will
+find it."
   ;; Instead of trying to piece things together from partial text
   ;; (which can be almost useless depending on Emacs version), we
   ;; monitor to the point where we have the next pdb prompt, and then
   ;; check all text from comint-last-input-end to process-mark.
   ;;
-  ;; KLM: It might be nice to provide an optional override, so this
-  ;; routine could be fed debugger output strings as the text
-  ;; argument, for deliberate application elsewhere.
-  ;;
-  ;; KLM: We're very conservative about clearing the overlay arrow, to
-  ;; minimize residue.  This means, for instance, that executing other
-  ;; pdb commands wipes out the highlight.
+  ;; Also, we're very conservative about clearing the overlay arrow,
+  ;; to minimize residue.  This means, for instance, that executing
+  ;; other pdb commands wipe out the highlight.  You can always do a
+  ;; 'where' (aka 'w') PDB command to reveal the overlay arrow.
+
   (let* ((origbuf (current-buffer))
         (currproc (get-buffer-process origbuf)))
+
     (if (not (and currproc python-pdbtrack-do-tracking-p))
         (python-pdbtrack-overlay-arrow nil)
-      (let* (;(origdir default-directory)
-             (procmark (process-mark currproc))
+
+      (let* ((procmark (process-mark currproc))
              (block (buffer-substring (max comint-last-input-end
                                            (- procmark
                                               python-pdbtrack-track-range))
                                       procmark))
-             fname lineno)
+             target target_fname target_lineno target_buffer)
+
         (if (not (string-match (concat python-pdbtrack-input-prompt "$") block))
             (python-pdbtrack-overlay-arrow nil)
-          (if (not (string-match
-                    (concat ".*" python-pdbtrack-stack-entry-regexp ".*")
-                    block))
-              (python-pdbtrack-overlay-arrow nil)
-            (setq fname (match-string 1 block)
-                  lineno (match-string 2 block))
-            (if (file-exists-p fname)
-                (progn
-                  (find-file-other-window fname)
-                  (goto-line (string-to-number lineno))
-                  (message "pdbtrack: line %s, file %s" lineno fname)
-                  (python-pdbtrack-overlay-arrow t)
-                  (pop-to-buffer origbuf t) )
-              (if (= (elt fname 0) ?\<)
-                  (message "pdbtrack: (Non-file source: '%s')" fname)
-                (message "pdbtrack: File not found: %s" fname)))))))))
+
+          (setq target (python-pdbtrack-get-source-buffer block))
+
+          (if (stringp target)
+              (progn
+                (python-pdbtrack-overlay-arrow nil)
+                (message "pdbtrack: %s" target))
+
+            (setq target_lineno (car target)
+                  target_buffer (cadr target)
+                  target_fname (buffer-file-name target_buffer))
+            (switch-to-buffer-other-window target_buffer)
+            (goto-char (point-min))
+            (forward-line (1- target_lineno))
+            (message "pdbtrack: line %s, file %s" target_lineno target_fname)
+            (python-pdbtrack-overlay-arrow t)
+            (pop-to-buffer origbuf t)
+            ;; in large shell buffers, above stuff may cause point to lag output
+            (goto-char procmark)
+            )))))
+  )
+
+(defun python-pdbtrack-get-source-buffer (block)
+  "Return line number and buffer of code indicated by block's traceback text.
+
+We look first to visit the file indicated in the trace.
+
+Failing that, we look for the most recently visited python-mode buffer
+with the same name or having the named function.
+
+If we're unable find the source code we return a string describing the
+problem."
+
+  (if (not (string-match python-pdbtrack-stack-entry-regexp block))
+
+      "Traceback cue not found"
+
+    (let* ((filename (match-string 1 block))
+           (lineno (string-to-number (match-string 2 block)))
+           (funcname (match-string 3 block))
+           funcbuffer)
+
+      (cond ((file-exists-p filename)
+             (list lineno (find-file-noselect filename)))
+
+            ((setq funcbuffer (python-pdbtrack-grub-for-buffer funcname lineno))
+             (if (string-match "/Script (Python)$" filename)
+                 ;; Add in number of lines for leading '##' comments:
+                 (setq lineno
+                       (+ lineno
+                          (with-current-buffer funcbuffer
+                            (if (equal (point-min)(point-max))
+                                0
+                              (count-lines
+                               (point-min)
+                               (max (point-min)
+                                    (string-match "^\\([^#]\\|#[^#]\\|#$\\)"
+                                                  (buffer-substring
+                                                   (point-min) (point-max)))
+                                    )))))))
+               (list lineno funcbuffer))
+
+            ((= (elt filename 0) ?\<)
+             (format "(Non-file source: '%s')" filename))
+
+            (t (format "Not found: %s(), %s" funcname filename)))
+      )
+    )
+  )
+
+(defun python-pdbtrack-grub-for-buffer (funcname lineno)
+  "Find recent python-mode buffer named, or having function named funcname."
+  (let ((buffers (buffer-list))
+        buf
+        got)
+    (while (and buffers (not got))
+      (setq buf (car buffers)
+            buffers (cdr buffers))
+      (if (and (with-current-buffer buf
+                 (string= major-mode "python-mode"))
+               (or (string-match funcname (buffer-name buf))
+                   (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+"
+                                         funcname "\\s-*(")
+                                 (with-current-buffer buf
+                                   (buffer-substring (point-min)
+                                                     (point-max))))))
+          (setq got buf)))
+    got))
 
 (defun python-toggle-shells (arg)
   "Toggles between the CPython and JPython shells.
@@ -2801,6 +2773,26 @@ Programmatically, ARG can also be one of the symbols `cpython' or
            mode-name "JPython")))
     (message "Using the %s shell" msg)))
 
+;; Python subprocess utilities and filters
+(defun python-execute-file (proc filename)
+  "Send to Python interpreter process PROC \"execfile('FILENAME')\".
+Make that process's buffer visible and force display.  Also make
+comint believe the user typed this string so that
+`kill-output-from-shell' does The Right Thing."
+  (let ((curbuf (current-buffer))
+       (procbuf (process-buffer proc))
+;      (comint-scroll-to-bottom-on-output t)
+       (msg (format "## working on region in file %s...\n" filename))
+        ;; add some comment, so that we can filter it out of history
+       (cmd (format "execfile(r'%s') # PYTHON-MODE\n" filename)))
+    (unwind-protect
+       (with-current-buffer procbuf
+         (goto-char (point-max))
+         (move-marker (process-mark proc) (point))
+         (funcall (process-filter proc) proc msg))
+      (set-buffer curbuf))
+    (process-send-string proc cmd)))
+
 ;;;###autoload
 (defun python-shell (&optional argprompt)
   "Start an interactive Python interpreter in another window.
@@ -2815,7 +2807,7 @@ command is used to switch to an existing process, only when a new
 process is started.  If you use this, you will probably want to ensure
 that the current arguments are retained (they will be included in the
 prompt).  This argument is ignored when this function is called
-programmatically, or when running in Emacs 19.34 or older.
+programmatically.
 
 Note: You can toggle between using the CPython interpreter and the
 JPython interpreter by hitting \\[python-toggle-shells].  This toggles
@@ -2840,12 +2832,13 @@ interaction between undo and process filters; the same problem exists in
 non-Python process buffers using the default (Emacs-supplied) process
 filter."
   (interactive "P")
+  (require 'ansi-color) ; For ipython
   ;; Set the default shell if not already set
   (when (null python-which-shell)
     (python-toggle-shells python-default-interpreter))
   (let ((args python-which-args))
     (when (and argprompt
-              (interactive-p)
+              (called-interactively-p 'interactive)
               (fboundp 'split-string))
       ;; TBD: Perhaps force "-i" in the final list?
       (setq args (split-string
@@ -2856,15 +2849,12 @@ filter."
                               ))))
     (switch-to-buffer-other-window
      (apply 'make-comint python-which-bufname python-which-shell nil args))
-    (make-local-variable 'comint-prompt-regexp)
-    (set-process-sentinel (get-buffer-process (current-buffer)) 'python-sentinel)
-    (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
+    (set-process-sentinel (get-buffer-process (current-buffer))
+                          'python-sentinel)
+    (python--set-prompt-regexp)
     (add-hook 'comint-output-filter-functions
              'python-comint-output-filter-function nil t)
     ;; pdbtrack
-    (add-hook 'comint-output-filter-functions
-             'python-pdbtrack-track-stack-file nil t)
-    (setq python-pdbtrack-do-tracking-p t)
     (set-syntax-table python-mode-syntax-table)
     (use-local-map python-shell-map)))
 
@@ -2894,5 +2884,4 @@ filter."
 (provide 'python)
 (provide 'python-21)
 
-;; arch-tag: 6fce1d99-a704-4de9-ba19-c6e4912b0554
 ;;; python.el ends here