These changes to python-mode.el v4.75 from Sourceforge fix various
problems, including several from the current Debian and Sourceforge
bug lists.  They also make some general cleanups.  However, see the
new mode in the current Emacs 22 development source and the version
adapted for Emacs 21 in python-21.el.

2005-08-17  Dave Love  <fx@gnu.org>

	* python-mode.el: Doc fixes.
	(ansi-color-filter-apply): Autoload.
	(Font-lock-mode-hook): Don't add `py-font-lock-mode-hook'
	globally.
	(py-traceback-line-re): Use defconst.
	(py-shell-map): Set parent to comint-mode-map.
	(py-execute-region): Use `shell', not `py-which-shell'.
	(read-shell-command): Delete alias.
	(info-look): Don't require.
	("info-look"): Use eval-after-load and fix version treatment in
	the form.
	(py-point, py-postprocess-output-buffer): Don't use
	{beginning,end}-of-buffer.

2003-12-01  Dave Love  <fx@gnu.org>

	* python-mode.el: Doc fixes.
	(custom, cl, compile): Don't require.
	(compile-internal): Autoload.
	(comint-last-input-end): Defvar when compiling.
	(py-quote-syntax, py-font-lock-syntactic-keywords)
	(py-mark-active, py-outline-level, python-mode-unload-hook): New.
	(py-keep-region-active, py-electric-delete): Avoid compilation
	warning in Emacs.
	(py-highlight-line, py-mouseto-exception): Add Emacs case.
	(py-in-literal): Define separate cases for Emacs and XEmacs, and
	avoid warning.  Simplify Emacs case.
	(py-fast-in-literal): Deleted.
	(py-which-shell, py-which-args, py-which-bufname): Move before
	use.
	(python-mode): Set parse-sexp-lookup-properties, outline-regexp,
	outline-level, open-paren-in-column-0-is-defun-start.  Modify
	font-lock-defaults value.
	(py-output-buffer): defvar, not defconst.
	(py-help-at-point): Avoid `search'.
	(py-temp-directory): Maybe use temporary-file-directory.
	(py-menu, py-shift-region-left, py-shift-region-right): Fix use of
	`(mark)'.
	(py-beginning-of-def-or-class): Re-run if it lands in a string.
	(py-goto-beginning-of-tqs): Don't lose if delim is t.
	(py-shell-alist): Don't quote cdrs.
	(py-mode-map, py-shell-map, py-mode-output-map)
	(py-mode-syntax-table, py-dotted-expression-syntax-table): Define
	inside defvar.
	(py-imenu-create-index-engine): Avoid `first', `second'.
	(py-choose-shell-by-shebang): Use py-shell-alist correctly.
	(py-shell): Only add to comint-output-filter-functions locally.
	Set indent-line-function.
	(py-execute-region): Fix choosing shell.
	(py-mark-block): Activate mark.
	(py-python-version): New.  Use it with info-lookup-maybe-add-help.
	(debug-ignored-errors): Add errors used here.
	(py-shell-map): Don't bind tab.
	(py-pychecker-run): Use read-shell-command conditionally.
	(py-mode-output-map): Maybe bind mouse-2.  Use suppress-keymap.

--- python-mode.el	2005/08/16 12:30:49	1.1.1.1
+++ python-mode.el	2006/05/21 15:00:28
@@ -1,6 +1,8 @@
 ;;; python-mode.el --- Major mode for editing Python programs
 
 ;; Copyright (C) 1992,1993,1994  Tim Peters
+;; Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+;;   (changes made by Dave Love <fx@gnu.org>)
 
 ;; Author: 2003-2004 http://sf.net/projects/python-mode
 ;;         1995-2002 Barry A. Warsaw
@@ -18,6 +20,9 @@
 ;; organization, is hereby granted, provided that the above copyright
 ;; notice and this paragraph appear in all copies.
 
+;; This file contains significant bits of GPL'd code, so it must be
+;; under the GPL.  -- fx
+
 ;;; Commentary:
 
 ;; This is a major mode for editing Python programs.  It was developed by Tim
@@ -42,7 +47,7 @@
 ;; byte-compile it.  To set up Emacs to automatically edit files ending in
 ;; ".py" using python-mode add the following to your ~/.emacs file (GNU
 ;; Emacs) or ~/.xemacs/init.el file (XEmacs):
-;;    (setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist))
+;;    (setq auto-mode-alist (cons '("\\.py\\'" . python-mode) auto-mode-alist))
 ;;    (setq interpreter-mode-alist (cons '("python" . python-mode)
 ;;                                       interpreter-mode-alist))
 ;;    (autoload 'python-mode "python-mode" "Python editing mode." t)
@@ -61,6 +66,9 @@
 ;; It does contain links to other packages that you might find useful,
 ;; such as pdb interfaces, OO-Browser links, etc.
 
+;; Note that the Emacs 21 support for correct treatment of
+;; triply-quoted string syntax requires font-lock to be turned on.
+
 ;; BUG REPORTING:
 
 ;; As mentioned above, please use the SourceForge Python project for
@@ -71,16 +79,16 @@
 ;; suggestions and other comments to python-mode@python.org.
 
 ;; When in a Python mode buffer, do a C-h m for more help.  It's
-;; doubtful that a texinfo manual would be very useful, but if you
+;; doubtful that a Texinfo manual would be very useful, but if you
 ;; want to contribute one, I'll certainly accept it!
 
 ;;; Code:
 
 (require 'comint)
-(require 'custom)
-(require 'cl)
-(require 'compile)
-(require 'ansi-color)
+(autoload 'ansi-color-filter-apply "ansi-color")
+(autoload 'compile-internal "compile")
+(eval-when-compile
+  (defvar comint-last-input-end))	; not actually bound in comint
 
 
 ;; user definable variables
@@ -219,22 +227,25 @@
   :group 'python)
 
 (defcustom py-temp-directory
-  (let ((ok '(lambda (x)
-	       (and x
-		    (setq x (expand-file-name x)) ; always true
-		    (file-directory-p x)
-		    (file-writable-p x)
-		    x))))
-    (or (funcall ok (getenv "TMPDIR"))
-	(funcall ok "/usr/tmp")
-	(funcall ok "/tmp")
-	(funcall ok "/var/tmp")
-	(funcall ok  ".")
-	(error
-	 "Couldn't find a usable temp directory -- set `py-temp-directory'")))
+  (if (boundp 'temporary-file-directory)
+      temporary-file-directory
+    (let ((ok '(lambda (x)
+		 (and x
+		      (setq x (expand-file-name x)) ; always true
+		      (file-directory-p x)
+		      (file-writable-p x)
+		      x))))
+      (or (funcall ok (getenv "TMPDIR"))
+	  (funcall ok "/usr/tmp")
+	  (funcall ok "/tmp")
+	  (funcall ok "/var/tmp")
+	  (funcall ok  ".")
+	  (error
+	   "Couldn't find a usable temp directory -- set `py-temp-directory'"))))
   "*Directory used for temporary files created by a *Python* process.
-By default, the first directory from this list that exists and that you
-can write into: the value (if any) of the environment variable TMPDIR,
+If `temporary-file-directory' is bound, its value.
+Otherwise default to the first directory from this that is writable:
+the value (if any) of the environment variable TMPDIR,
 /usr/tmp, /tmp, /var/tmp, or the current directory."
   :type 'string
   :group 'python)
@@ -347,10 +358,11 @@
   :tag "Pychecker Command Args")
 
 (defvar py-shell-alist
-  '(("jython" . 'jython)
-    ("python" . 'cpython))
-  "*Alist of interpreters and python shells. Used by `py-choose-shell'
-to select the appropriate python interpreter mode for a file.")
+  '(("jython" . jython)
+    ("python" . cpython))
+  "*Alist of interpreters and python shells.
+Used by `py-choose-shell' to select the appropriate python interpreter
+mode for a file.")
 
 (defcustom py-shell-input-prompt-1-regexp "^>>> "
   "*A regular expression to match the input prompt of the shell."
@@ -358,15 +370,15 @@
   :group 'python)
 
 (defcustom py-shell-input-prompt-2-regexp "^[.][.][.] "
-  "*A regular expression to match the input prompt of the shell after the
-  first line of input."
+  "*A regular expression to match the input prompt of the shell.
+Applies after the first line of input."
   :type 'string
   :group 'python)
 
 (defcustom py-shell-switch-buffers-on-execute t
-  "*Controls switching to the Python buffer where commands are
-  executed.  When non-nil the buffer switches to the Python buffer, if
-  not no switching occurs."
+  "*Controls switching to the Python buffer where commands are executed.
+When non-nil the buffer switches to the Python buffer, otherwise
+no switching occurs."
   :type 'boolean
   :group 'python)
 
@@ -410,7 +422,6 @@
   (or (face-differs-from-default-p 'py-decorators-face)
       (copy-face 'py-pseudo-keyword-face 'py-decorators-face))
   )
-(add-hook 'font-lock-mode-hook 'py-font-lock-mode-hook)
 
 (defvar python-font-lock-keywords
   (let ((kw1 (mapconcat 'identity
@@ -494,6 +505,50 @@
   "Additional expressions to highlight in Python mode.")
 (put 'python-mode 'font-lock-defaults '(python-font-lock-keywords))
 
+(defun py-quote-syntax (n)
+  "Put syntax-table property correctly on triple quote.
+Used in syntactic keywords.  N is the match number (1 or 2)."
+  ;; Given a triple quote, we have to look backwards for a previous
+  ;; occurrence of the sequence to know whether this is an opening or
+  ;; closing sequence.  Perhaps this is better done with Emacs 21.4
+  ;; syntax.el.
+  (let ((tag (save-excursion
+	       (goto-char (match-beginning 0))
+	       (unless (eq ?\\ (char-before))
+		 ;; Look for a previous string fence.
+		 (if (or (zerop (skip-syntax-backward "^|"))
+			 (bobp))
+		     ;; No previous string fence.
+		     'start
+		   (if (eq (char-before) (char-after (match-beginning 0)))
+		       ;; Fence for matching quote.
+		       (if (eq (char-before) (char-after))
+			   'end		; fence was end of string
+			 'start)	; fence was beginning
+		     ;; Else non-matching quote.  Start new string if fence
+		     ;; is end of string.
+		     (unless (eq (char-before) (char-after))
+		       'start)))))))
+    (if (eq tag 'start)
+	(if (= n 1) ; Triple quote starts new string.  Put property at start.
+	    (eval-when-compile (string-to-syntax "|")))
+      (if (eq tag 'end)	  ; End existing string.  Put property at end.
+	  (if (= n 2)
+	      (eval-when-compile (string-to-syntax "|"))))
+      ;; Otherwise, the syntax property is nil, which is OK.
+      )))
+
+;; Note that the syntax-table property loses at beginning of buffer as
+;; of Emacs sources Nov. '03.  You at least can't `backward-sexp' over
+;; a leading triple-quoted docstring.
+
+(defconst py-font-lock-syntactic-keywords
+  ;; Make outside chars of matching triple-quote sequences into
+  ;; generic string delimiters.  Fixme: Is there a better way?
+  '(("\\(\\s\"\\)\\1\\(\\1\\)"
+     (1 (py-quote-syntax 1))
+     (2 (py-quote-syntax 2)))))
+
 ;; have to bind py-file-queue before installing the kill-emacs-hook
 (defvar py-file-queue nil
   "Queue of Python temp files awaiting execution.
@@ -568,14 +623,13 @@
 	  "\\)")
   "Regular expression matching lines not to dedent after.")
 
-(defvar py-traceback-line-re
+(defconst py-traceback-line-re
   "[ \t]+File \"\\([^\"]+\\)\", line \\([0-9]+\\)"
   "Regular expression that describes tracebacks.")
 
 ;; pdbtrack constants
 (defconst py-pdbtrack-stack-entry-regexp
-;  "^> \\([^(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
-  "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
+  "^> \\([^(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()"
   "Regular expression pdbtrack uses to find a stack trace entry.")
 
 (defconst py-pdbtrack-input-prompt "\n[(<]*[Pp]db[>)]+ "
@@ -598,8 +652,8 @@
 
 (make-obsolete-variable 'jpython-mode-hook 'jython-mode-hook)
 (defvar jython-mode-hook nil
-  "*Hook called by `jython-mode'. `jython-mode' also calls
-`python-mode-hook'.")
+  "*Hook called by `jython-mode'.
+`jython-mode' also calls `python-mode-hook'.")
 
 (defvar py-shell-hook nil
   "*Hook called by `py-shell'.")
@@ -609,162 +663,164 @@
 (and (fboundp 'make-obsolete-variable)
      (make-obsolete-variable 'py-mode-hook 'python-mode-hook))
 
-(defvar py-mode-map ()
+(defvar py-mode-map
+  (let ((py-mode-map (make-sparse-keymap)))
+    ;; electric keys
+    (define-key py-mode-map ":" 'py-electric-colon)
+    ;; indentation level modifiers
+    (define-key py-mode-map "\C-c\C-l"  'py-shift-region-left)
+    (define-key py-mode-map "\C-c\C-r"  'py-shift-region-right)
+    (define-key py-mode-map "\C-c<"     'py-shift-region-left)
+    (define-key py-mode-map "\C-c>"     'py-shift-region-right)
+    ;; subprocess commands
+    (define-key py-mode-map "\C-c\C-c"  'py-execute-buffer)
+    (define-key py-mode-map "\C-c\C-m"  'py-execute-import-or-reload)
+    (define-key py-mode-map "\C-c\C-s"  'py-execute-string)
+    ;; !! Next two violate major mode conventions.
+    (define-key py-mode-map "\C-c|"     'py-execute-region)
+    (define-key py-mode-map "\C-c!"     'py-shell)
+    (define-key py-mode-map "\e\C-x"    'py-execute-def-or-class)
+    (define-key py-mode-map "\C-c\C-t"  'py-toggle-shells)
+    ;; Caution!  Enter here at your own risk.  We are trying to support
+    ;; several behaviors and it gets disgusting. :-( This logic ripped
+    ;; largely from CC Mode.
+    ;;
+    ;; In XEmacs 19, Emacs 19, and Emacs 20, we use this to bind
+    ;; backwards deletion behavior to DEL, which both Delete and
+    ;; Backspace get translated to.  There's no way to separate this
+    ;; behavior in a clean way, so deal with it!  Besides, it's been
+    ;; this way since the dawn of time.
+    (if (not (boundp 'delete-key-deletes-forward))
+	;; (This is the right thing in Emacs 21, where
+	;; `normal-erase-is-backspace-mode' takes care of things.)
+	(define-key py-mode-map "\177" 'py-electric-backspace)
+      ;; However, XEmacs 20 actually achieved enlightenment.  It is
+      ;; possible to sanely define both backward and forward deletion
+      ;; behavior under X separately (TTYs are forever beyond hope, but
+      ;; who cares?  XEmacs 20 does the right thing with these too).
+      (define-key py-mode-map [delete]    'py-electric-delete)
+      (define-key py-mode-map [backspace] 'py-electric-backspace))
+    ;; Separate M-BS from C-M-h.  The former should remain
+    ;; backward-kill-word.
+    (define-key py-mode-map [(control meta h)] 'py-mark-def-or-class)
+    (define-key py-mode-map "\C-c\C-k"  'py-mark-block)
+    ;; Miscellaneous
+    (define-key py-mode-map "\C-c:"     'py-guess-indent-offset)
+    (define-key py-mode-map "\C-c\t"    'py-indent-region)
+    (define-key py-mode-map "\C-c\C-d"  'py-pdbtrack-toggle-stack-tracking)
+    (define-key py-mode-map "\C-c\C-n"  'py-next-statement)
+    (define-key py-mode-map "\C-c\C-p"  'py-previous-statement)
+    (define-key py-mode-map "\C-c\C-u"  'py-goto-block-up)
+    ;; !! Next two violate major mode conventions.
+    (define-key py-mode-map "\C-c#"     'py-comment-region)
+    (define-key py-mode-map "\C-c?"     'py-describe-mode)
+    ;; This violates the convention for getting help on prefix maps.
+    (define-key py-mode-map "\C-c\C-h"  'py-help-at-point)
+    (unless (boundp 'beginning-of-defun-function)
+      (define-key py-mode-map "\e\C-a"    'py-beginning-of-def-or-class)
+      (define-key py-mode-map "\e\C-e"    'py-end-of-def-or-class))
+    ;; !! Next two violate major mode conventions.
+    (define-key py-mode-map "\C-c-"     'py-up-exception)
+    (define-key py-mode-map "\C-c="     'py-down-exception)
+    ;; stuff that is `standard' but doesn't interface well with
+    ;; python-mode, which forces us to rebind to special commands
+    ;;   In Emacs, defining `beginning-of-defun-function',
+    ;;   `end-of-defun-function' would take care of this, modulo doc
+    ;;   about prefix arg.  -- fx
+    (define-key py-mode-map "\C-xnd"    'py-narrow-to-defun)
+    ;; information
+    (define-key py-mode-map "\C-c\C-b" 'py-submit-bug-report)
+    (define-key py-mode-map "\C-c\C-v" 'py-version)
+    (define-key py-mode-map "\C-c\C-w" 'py-pychecker-run)
+    ;; shadow global bindings for newline-and-indent w/ the py- version.
+    ;; BAW - this is extremely bad form, but I'm not going to change it
+    ;; for now.
+    (mapcar #'(lambda (key)
+		(define-key py-mode-map key 'py-newline-and-indent))
+	    (where-is-internal 'newline-and-indent))
+    ;; Force RET to be py-newline-and-indent even if it didn't get
+    ;; mapped by the above code.  motivation: Emacs' default binding for
+    ;; RET is `newline' and C-j is `newline-and-indent'.  Most Pythoneers
+    ;; expect RET to do a `py-newline-and-indent' and any Emacsers who
+    ;; dislike this are probably knowledgeable enough to do a rebind.
+    ;; However, we do *not* change C-j since many Emacsers have already
+    ;; swapped RET and C-j and they don't want C-j bound to `newline' to
+    ;; change.
+    (define-key py-mode-map "\C-m" 'py-newline-and-indent)
+    py-mode-map)
   "Keymap used in `python-mode' buffers.")
-(if py-mode-map
-    nil
-  (setq py-mode-map (make-sparse-keymap))
-  ;; electric keys
-  (define-key py-mode-map ":" 'py-electric-colon)
-  ;; indentation level modifiers
-  (define-key py-mode-map "\C-c\C-l"  'py-shift-region-left)
-  (define-key py-mode-map "\C-c\C-r"  'py-shift-region-right)
-  (define-key py-mode-map "\C-c<"     'py-shift-region-left)
-  (define-key py-mode-map "\C-c>"     'py-shift-region-right)
-  ;; subprocess commands
-  (define-key py-mode-map "\C-c\C-c"  'py-execute-buffer)
-  (define-key py-mode-map "\C-c\C-m"  'py-execute-import-or-reload)
-  (define-key py-mode-map "\C-c\C-s"  'py-execute-string)
-  (define-key py-mode-map "\C-c|"     'py-execute-region)
-  (define-key py-mode-map "\e\C-x"    'py-execute-def-or-class)
-  (define-key py-mode-map "\C-c!"     'py-shell)
-  (define-key py-mode-map "\C-c\C-t"  'py-toggle-shells)
-  ;; Caution!  Enter here at your own risk.  We are trying to support
-  ;; several behaviors and it gets disgusting. :-( This logic ripped
-  ;; largely from CC Mode.
-  ;;
-  ;; In XEmacs 19, Emacs 19, and Emacs 20, we use this to bind
-  ;; backwards deletion behavior to DEL, which both Delete and
-  ;; Backspace get translated to.  There's no way to separate this
-  ;; behavior in a clean way, so deal with it!  Besides, it's been
-  ;; this way since the dawn of time.
-  (if (not (boundp 'delete-key-deletes-forward))
-      (define-key py-mode-map "\177" 'py-electric-backspace)
-    ;; However, XEmacs 20 actually achieved enlightenment.  It is
-    ;; possible to sanely define both backward and forward deletion
-    ;; behavior under X separately (TTYs are forever beyond hope, but
-    ;; who cares?  XEmacs 20 does the right thing with these too).
-    (define-key py-mode-map [delete]    'py-electric-delete)
-    (define-key py-mode-map [backspace] 'py-electric-backspace))
-  ;; Separate M-BS from C-M-h.  The former should remain
-  ;; backward-kill-word.
-  (define-key py-mode-map [(control meta h)] 'py-mark-def-or-class)
-  (define-key py-mode-map "\C-c\C-k"  'py-mark-block)
-  ;; Miscellaneous
-  (define-key py-mode-map "\C-c:"     'py-guess-indent-offset)
-  (define-key py-mode-map "\C-c\t"    'py-indent-region)
-  (define-key py-mode-map "\C-c\C-d"  'py-pdbtrack-toggle-stack-tracking)
-  (define-key py-mode-map "\C-c\C-n"  'py-next-statement)
-  (define-key py-mode-map "\C-c\C-p"  'py-previous-statement)
-  (define-key py-mode-map "\C-c\C-u"  'py-goto-block-up)
-  (define-key py-mode-map "\C-c#"     'py-comment-region)
-  (define-key py-mode-map "\C-c?"     'py-describe-mode)
-  (define-key py-mode-map "\C-c\C-h"  'py-help-at-point)
-  (define-key py-mode-map "\e\C-a"    'py-beginning-of-def-or-class)
-  (define-key py-mode-map "\e\C-e"    'py-end-of-def-or-class)
-  (define-key py-mode-map "\C-c-"     'py-up-exception)
-  (define-key py-mode-map "\C-c="     'py-down-exception)
-  ;; stuff that is `standard' but doesn't interface well with
-  ;; python-mode, which forces us to rebind to special commands
-  (define-key py-mode-map "\C-xnd"    'py-narrow-to-defun)
-  ;; information
-  (define-key py-mode-map "\C-c\C-b" 'py-submit-bug-report)
-  (define-key py-mode-map "\C-c\C-v" 'py-version)
-  (define-key py-mode-map "\C-c\C-w" 'py-pychecker-run)
-  ;; shadow global bindings for newline-and-indent w/ the py- version.
-  ;; BAW - this is extremely bad form, but I'm not going to change it
-  ;; for now.
-  (mapcar #'(lambda (key)
-	      (define-key py-mode-map key 'py-newline-and-indent))
-	  (where-is-internal 'newline-and-indent))
-  ;; Force RET to be py-newline-and-indent even if it didn't get
-  ;; mapped by the above code.  motivation: Emacs' default binding for
-  ;; RET is `newline' and C-j is `newline-and-indent'.  Most Pythoneers
-  ;; expect RET to do a `py-newline-and-indent' and any Emacsers who
-  ;; dislike this are probably knowledgeable enough to do a rebind.
-  ;; However, we do *not* change C-j since many Emacsers have already
-  ;; swapped RET and C-j and they don't want C-j bound to `newline' to
-  ;; change.
-  (define-key py-mode-map "\C-m" 'py-newline-and-indent)
-  )
 
-(defvar py-mode-output-map nil
+(defvar py-mode-output-map
+  (let ((py-mode-output-map (make-sparse-keymap)))
+    (suppress-keymap py-mode-output-map t)
+    (define-key py-mode-output-map (if (lookup-key global-map [button2])
+				       [button2] ; XEmacs
+				     [mouse-2])	; Emacs
+      'py-mouseto-exception)
+    (define-key py-mode-output-map "\C-c\C-c" 'py-goto-exception)
+    py-mode-output-map)
   "Keymap used in *Python Output* buffers.")
-(if py-mode-output-map
-    nil
-  (setq py-mode-output-map (make-sparse-keymap))
-  (define-key py-mode-output-map [button2]  'py-mouseto-exception)
-  (define-key py-mode-output-map "\C-c\C-c" 'py-goto-exception)
-  ;; TBD: Disable all self-inserting keys.  This is bogus, we should
-  ;; really implement this as *Python Output* buffer being read-only
-  (mapcar #' (lambda (key)
-	       (define-key py-mode-output-map key
-		 #'(lambda () (interactive) (beep))))
-	     (where-is-internal 'self-insert-command))
-  )
 
-(defvar py-shell-map nil
+(defvar py-shell-map
+  (let ((py-shell-map (make-sparse-keymap)))
+    (set-keymap-parent py-shell-map comint-mode-map)
+    (define-key py-shell-map "\C-c-" 'py-up-exception)
+    (define-key py-shell-map "\C-c=" 'py-down-exception)
+    py-shell-map)
   "Keymap used in *Python* shell buffers.")
-(if py-shell-map
-    nil
-  (setq py-shell-map (copy-keymap comint-mode-map))
-  (define-key py-shell-map [tab]   'tab-to-tab-stop)
-  (define-key py-shell-map "\C-c-" 'py-up-exception)
-  (define-key py-shell-map "\C-c=" 'py-down-exception)
-  )
 
-(defvar py-mode-syntax-table nil
+(defvar py-mode-syntax-table
+  (let ((py-mode-syntax-table (make-syntax-table)))
+    (modify-syntax-entry ?\( "()" py-mode-syntax-table)
+    (modify-syntax-entry ?\) ")(" py-mode-syntax-table)
+    (modify-syntax-entry ?\[ "(]" py-mode-syntax-table)
+    (modify-syntax-entry ?\] ")[" py-mode-syntax-table)
+    (modify-syntax-entry ?\{ "(}" py-mode-syntax-table)
+    (modify-syntax-entry ?\} "){" py-mode-syntax-table)
+    ;; Add operator symbols misassigned in the std table
+    (modify-syntax-entry ?\$ "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\% "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\& "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\* "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\+ "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\- "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\/ "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\< "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\= "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\> "."  py-mode-syntax-table)
+    (modify-syntax-entry ?\| "."  py-mode-syntax-table)
+    ;; For historical reasons, underscore is word class instead of
+    ;; symbol class.  GNU conventions say it should be symbol class, but
+    ;; there's a natural conflict between what major mode authors want
+    ;; and what users expect from `forward-word' and `backward-word'.
+    ;; [What does that mean?  What's special about Python?  --fx]
+    ;; Guido and I have hashed this out and have decided to keep
+    ;; underscore in word class.  If you're tempted to change it, try
+    ;; binding M-f and M-b to py-forward-into-nomenclature and
+    ;; py-backward-into-nomenclature instead.  This doesn't help in all
+    ;; situations where you'd want the different behavior
+    ;; (e.g. backward-kill-word).
+    (modify-syntax-entry ?\_ "w"  py-mode-syntax-table)
+    ;; Both single quote and double quote are string delimiters
+    (modify-syntax-entry ?\' "\"" py-mode-syntax-table)
+    (modify-syntax-entry ?\" "\"" py-mode-syntax-table)
+    ;; backquote is open and close paren
+    (modify-syntax-entry ?\` "$"  py-mode-syntax-table)
+    ;; comment delimiters
+    (modify-syntax-entry ?\# "<"  py-mode-syntax-table)
+    (modify-syntax-entry ?\n ">"  py-mode-syntax-table)
+    py-mode-syntax-table)
   "Syntax table used in `python-mode' buffers.")
-(when (not py-mode-syntax-table)
-  (setq py-mode-syntax-table (make-syntax-table))
-  (modify-syntax-entry ?\( "()" py-mode-syntax-table)
-  (modify-syntax-entry ?\) ")(" py-mode-syntax-table)
-  (modify-syntax-entry ?\[ "(]" py-mode-syntax-table)
-  (modify-syntax-entry ?\] ")[" py-mode-syntax-table)
-  (modify-syntax-entry ?\{ "(}" py-mode-syntax-table)
-  (modify-syntax-entry ?\} "){" py-mode-syntax-table)
-  ;; Add operator symbols misassigned in the std table
-  (modify-syntax-entry ?\$ "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\% "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\& "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\* "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\+ "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\- "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\/ "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\< "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\= "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\> "."  py-mode-syntax-table)
-  (modify-syntax-entry ?\| "."  py-mode-syntax-table)
-  ;; For historical reasons, underscore is word class instead of
-  ;; symbol class.  GNU conventions say it should be symbol class, but
-  ;; there's a natural conflict between what major mode authors want
-  ;; and what users expect from `forward-word' and `backward-word'.
-  ;; Guido and I have hashed this out and have decided to keep
-  ;; underscore in word class.  If you're tempted to change it, try
-  ;; binding M-f and M-b to py-forward-into-nomenclature and
-  ;; py-backward-into-nomenclature instead.  This doesn't help in all
-  ;; situations where you'd want the different behavior
-  ;; (e.g. backward-kill-word).
-  (modify-syntax-entry ?\_ "w"  py-mode-syntax-table)
-  ;; Both single quote and double quote are string delimiters
-  (modify-syntax-entry ?\' "\"" py-mode-syntax-table)
-  (modify-syntax-entry ?\" "\"" py-mode-syntax-table)
-  ;; backquote is open and close paren
-  (modify-syntax-entry ?\` "$"  py-mode-syntax-table)
-  ;; comment delimiters
-  (modify-syntax-entry ?\# "<"  py-mode-syntax-table)
-  (modify-syntax-entry ?\n ">"  py-mode-syntax-table)
-  )
 
 ;; An auxiliary syntax table which places underscore and dot in the
 ;; symbol class for simplicity
-(defvar py-dotted-expression-syntax-table nil
+(defvar py-dotted-expression-syntax-table
+  (let ((py-dotted-expression-syntax-table
+	 (copy-syntax-table py-mode-syntax-table)))
+    (modify-syntax-entry ?_ "_" py-dotted-expression-syntax-table)
+    (modify-syntax-entry ?. "_" py-dotted-expression-syntax-table)
+    py-dotted-expression-syntax-table)
   "Syntax table used to identify Python dotted expressions.")
-(when (not py-dotted-expression-syntax-table)
-  (setq py-dotted-expression-syntax-table
-	(copy-syntax-table py-mode-syntax-table))
-  (modify-syntax-entry ?_ "_" py-dotted-expression-syntax-table)
-  (modify-syntax-entry ?. "_" py-dotted-expression-syntax-table))
 
 
 
@@ -778,13 +834,13 @@
 (defsubst py-keep-region-active ()
   "Keep the region active in XEmacs."
   ;; Ignore byte-compiler warnings you might see.  Also note that
-  ;; FSF's Emacs 19 does it differently; its policy doesn't require us
+  ;; Emacs does it differently; its policy doesn't require us
   ;; to take explicit action.
-  (and (boundp 'zmacs-region-stays)
-       (setq zmacs-region-stays t)))
+  (if (boundp 'zmacs-region-stays)
+      (setq zmacs-region-stays t)))
 
 (defsubst py-point (position)
-  "Returns the value of point at certain commonly referenced POSITIONs.
+  "Return the value of point at certain commonly referenced POSITIONs.
 POSITION can be one of the following symbols:
 
   bol  -- beginning of line
@@ -804,8 +860,8 @@
      ((eq position 'bod) (py-beginning-of-def-or-class 'either))
      ((eq position 'eod) (py-end-of-def-or-class 'either))
      ;; Kind of funny, I know, but useful for py-up-exception.
-     ((eq position 'bob) (beginning-of-buffer))
-     ((eq position 'eob) (end-of-buffer))
+     ((eq position 'bob) (goto-char (point-min)))
+     ((eq position 'eob) (goto-char (point-max)))
      ((eq position 'boi) (back-to-indentation))
      ((eq position 'bos) (py-goto-initial-line))
      (t (error "Unknown buffer position requested: %s" position))
@@ -815,17 +871,26 @@
       (goto-char here))))
 
 (defsubst py-highlight-line (from to file line)
-  (cond
-   ((fboundp 'make-extent)
-    ;; XEmacs
-    (let ((e (make-extent from to)))
-      (set-extent-property e 'mouse-face 'highlight)
-      (set-extent-property e 'py-exc-info (cons file line))
-      (set-extent-property e 'keymap py-mode-output-map)))
-   (t
-    ;; Emacs -- Please port this!
-    )
-   ))
+  (if (featurep 'xemacs) ; help Emacs 21.4 compiler (c.f. feature tests)
+      (let ((e (make-extent from to)))
+	(set-extent-property e 'mouse-face 'highlight)
+	(set-extent-property e 'py-exc-info (cons file line))
+	(set-extent-property e 'keymap py-mode-output-map))
+    (let ((o (make-overlay from (1+ (min (point-max) to)))))
+      (overlay-put o 'mouse-face 'highlight)
+      (overlay-put o 'py-exc-info (cons file line))
+      ;; Fixme: Should this be `local-keymap'?
+      (overlay-put o 'keymap py-mode-output-map))))
+
+(eval-and-compile
+  (if (fboundp 'buffer-syntactic-context)
+;; XEmacs has a built-in function that should make this much quicker.
+;; In this case, lim is ignored
+(defun py-in-literal (&optional lim)
+  "Fast version of `py-in-literal', used only by XEmacs.
+Optional LIM is ignored."
+  ;; don't have to worry about context == 'block-comment
+  (buffer-syntactic-context))
 
 (defun py-in-literal (&optional lim)
   "Return non-nil if point is in a Python literal (a comment or string).
@@ -835,27 +900,17 @@
   ;; interface.
   ;;
   ;; WARNING: Watch out for infinite recursion.
-  (let* ((lim (or lim (py-point 'bod)))
-	 (state (parse-partial-sexp lim (point))))
-    (cond
-     ((nth 3 state) 'string)
-     ((nth 4 state) 'comment)
-     (t nil))))
-
-;; XEmacs has a built-in function that should make this much quicker.
-;; In this case, lim is ignored
-(defun py-fast-in-literal (&optional lim)
-  "Fast version of `py-in-literal', used only by XEmacs.
-Optional LIM is ignored."
-  ;; don't have to worry about context == 'block-comment
-  (buffer-syntactic-context))
-
-(if (fboundp 'buffer-syntactic-context)
-    (defalias 'py-in-literal 'py-fast-in-literal))
+  (nth 8 (parse-partial-sexp (or lim (py-point 'bod)) (point))))))
 
 
 
-;; Menu definitions, only relevent if you have the easymenu.el package
+(eval-and-compile
+  (if (boundp 'mark-active)
+      (defun py-mark-active ()		; Emacs
+	mark-active)
+    (defalias 'py-mark-active 'region-exists-p))) ; XEmacs
+
+;; Menu definitions, only relevant if you have the easymenu.el package
 ;; (standard in the latest Emacs 19 and XEmacs 19 distributions).
 (defvar py-menu nil
   "Menu for Python Mode.
@@ -866,20 +921,20 @@
      (easy-menu-define
       py-menu py-mode-map "Python Mode menu"
       '("Python"
-	["Comment Out Region"   py-comment-region  (mark)]
-	["Uncomment Region"     (py-comment-region (point) (mark) '(4)) (mark)]
+	["Comment Out Region"   py-comment-region  (py-mark-active)]
+	["Uncomment Region"     (py-comment-region (point) (mark) '(4)) (py-mark-active)]
 	"-"
 	["Mark current block"   py-mark-block t]
 	["Mark current def"     py-mark-def-or-class t]
 	["Mark current class"   (py-mark-def-or-class t) t]
 	"-"
-	["Shift region left"    py-shift-region-left (mark)]
-	["Shift region right"   py-shift-region-right (mark)]
+	["Shift region left"    py-shift-region-left (py-mark-active)]
+	["Shift region right"   py-shift-region-right (py-mark-active)]
 	"-"
 	["Import/reload file"   py-execute-import-or-reload t]
 	["Execute buffer"       py-execute-buffer t]
-	["Execute region"       py-execute-region (mark)]
-	["Execute def or class" py-execute-def-or-class (mark)]
+	["Execute region"       py-execute-region (py-mark-active)]
+	["Execute def or class" py-execute-def-or-class (py-mark-active)]
 	["Execute string"       py-execute-string t]
 	["Start interpreter..." py-shell t]
 	"-"
@@ -966,7 +1021,7 @@
 
 (defun py-imenu-create-index-function ()
   "Python interface function for the Imenu package.
-Finds all Python classes and functions/methods. Calls function
+Find all Python classes and functions/methods.  Call function
 \\[py-imenu-create-index-engine].  See that function for the details
 of how this works."
   (setq py-imenu-generic-regexp (car py-imenu-generic-expression)
@@ -999,9 +1054,9 @@
 the function \\[py-imenu-create-index-function].
 
 It works recursively by looking for all definitions at the current
-indention level.  When it finds one, it adds it to the alist.  If it
+indentation level.  When it finds one, it adds it to the alist.  If it
 finds a definition at a greater indentation level, it removes the
-previous definition from the alist. In its place it adds all
+previous definition from the alist.  In its place it adds all
 definitions found at the next indentation level.  When it finds a
 definition that is less indented then the current level, it returns
 the alist it has created thus far.
@@ -1015,8 +1070,8 @@
 	looking-p
 	def-name prev-name
 	cur-indent def-pos
-	(class-paren (first  py-imenu-generic-parens))
-	(def-paren   (second py-imenu-generic-parens)))
+	(class-paren (car  py-imenu-generic-parens))
+	(def-paren   (cadr py-imenu-generic-parens)))
     (setq looking-p
 	  (re-search-forward py-imenu-generic-regexp (point-max) t))
     (while looking-p
@@ -1101,9 +1156,8 @@
 			  "")))
 	 elt)
     ;; Map interpreter name to a mode.
-    (setq elt (assoc (file-name-nondirectory interpreter)
-		     py-shell-alist))
-    (and elt (caddr elt))))
+    (setq elt (cdr (assoc (file-name-nondirectory interpreter)
+			  py-shell-alist)))))
 
 
 
@@ -1126,7 +1180,8 @@
 
 
 (defun py-choose-shell ()
-  "Choose CPython or Jython mode. Returns the appropriate mode function.
+  "Choose CPython or Jython mode.
+Return the appropriate mode function.
 This does the following:
  - look for an interpreter with `py-choose-shell-by-shebang'
  - examine imports using `py-choose-shell-by-import'
@@ -1139,7 +1194,20 @@
 ;               ;; is only way to choose CPython
       ))
 
+
+;; for toggling between CPython and JPython
+(defvar py-which-shell nil)
+(defvar py-which-args  py-python-command-args)
+(defvar py-which-bufname "Python")
+(make-variable-buffer-local 'py-which-shell)
+(make-variable-buffer-local 'py-which-args)
+(make-variable-buffer-local 'py-which-bufname)
 
+(defun py-outline-level ()
+  "`outline-level' function for Python mode."
+  (save-excursion
+    (forward-to-indentation 0)
+    (/ (current-column) py-indent-offset)))
 ;;;###autoload
 (defun python-mode ()
   "Major mode for editing Python files.
@@ -1176,12 +1244,21 @@
   (make-local-variable 'indent-line-function)
   (make-local-variable 'add-log-current-defun-function)
   (make-local-variable 'fill-paragraph-function)
+  (make-local-variable 'parse-sexp-lookup-properties)
+  (make-local-variable 'outline-regexp)
+  (make-local-variable 'outline-level)
+  (make-local-variable 'open-paren-in-column-0-is-defun-start) ; Emacs 21.4
   ;;
   (set-syntax-table py-mode-syntax-table)
+  (add-hook (make-local-hook 'font-lock-mode-hook)
+	    'py-font-lock-mode-hook nil t)
   (setq major-mode              'python-mode
 	mode-name               "Python"
 	local-abbrev-table      python-mode-abbrev-table
-	font-lock-defaults      '(python-font-lock-keywords)
+ 	font-lock-defaults      '(python-font-lock-keywords nil nil nil nil
+ 				  (font-lock-syntactic-keywords
+ 				   . py-font-lock-syntactic-keywords))
+ 	parse-sexp-lookup-properties t
 	paragraph-separate      "^[ \t]*$"
 	paragraph-start         "^[ \t]*$"
 	require-final-newline   t
@@ -1196,7 +1273,9 @@
 	add-log-current-defun-function 'py-current-defun
 
 	fill-paragraph-function 'py-fill-paragraph
-	)
+ 	outline-regexp		"\\s-+\\(def\\|class\\)\\>"
+ 	outline-level		#'py-outline-level
+ 	open-paren-in-column-0-is-defun-start nil)
   (use-local-map py-mode-map)
   ;; add the menu
   (if py-menu
@@ -1240,8 +1319,7 @@
   "Major mode for editing Jython/Jython files.
 This is a simple wrapper around `python-mode'.
 It runs `jython-mode-hook' then calls `python-mode.'
-It is added to `interpreter-mode-alist' and `py-choose-shell'.
-"
+It is added to `interpreter-mode-alist' and `py-choose-shell'."
   (interactive)
   (python-mode)
   (py-toggle-shells 'jython)
@@ -1270,7 +1348,7 @@
 
 ;; electric characters
 (defun py-outdent-p ()
-  "Returns non-nil if the current line should dedent one level."
+  "Return non-nil if the current line should dedent one level."
   (save-excursion
     (and (progn (back-to-indentation)
 		(looking-at py-outdent-re))
@@ -1364,7 +1442,7 @@
     ))
 
 (defun py-pdbtrack-overlay-arrow (activation)
-  "Activate or de arrow at beginning-of-line in current buffer."
+  "Activate or deactivate arrow at beginning-of-line in current buffer."
   ;; This was derived/simplified from edebug-overlay-arrow
   (cond (activation
 	 (setq overlay-arrow-position (make-marker))
@@ -1389,7 +1467,7 @@
 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 remote scripts, eg, Zope's 'Script
-(Python)' - put a _copy_ of the script in a buffer named for the
+\(Python)' - put a _copy_ of the script in a buffer named for the
 script, and set to python-mode, and pdbtrack will find it.)"
   ;; Instead of trying to piece things together from partial text
   ;; (which can be almost useless depending on Emacs version), we
@@ -1434,7 +1512,7 @@
   )
 
 (defun py-pdbtrack-get-source-buffer (block)
-  "Return line number and buffer of code indicated by block's traceback text.
+  "Return line number and buffer of code indicated by BLOCK's traceback text.
 
 We look first to visit the file indicated in the trace.
 
@@ -1481,10 +1559,10 @@
   )
 
 (defun py-pdbtrack-grub-for-buffer (funcname lineno)
-  "Find most recent buffer itself named or having function funcname.
+  "Find most recent buffer itself named or having function FUNCNAME.
 
 We walk the buffer-list history for python-mode buffers that are
-named for funcname or define a function funcname."
+named for FUNCNAME or define a function FUNCNAME."
   (let ((buffers (buffer-list))
         buf
         got)
@@ -1509,7 +1587,7 @@
   (let (line file bol err-p)
     (save-excursion
       (set-buffer buf)
-      (beginning-of-buffer)
+      (goto-char (point-min))
       (while (re-search-forward py-traceback-line-re nil t)
 	(setq file (match-string 1)
 	      line (string-to-int (match-string 2))
@@ -1528,19 +1606,11 @@
 ;; only used when (memq 'broken-temp-names py-emacs-features)
 (defvar py-serial-number 0)
 (defvar py-exception-buffer nil)
-(defconst py-output-buffer "*Python Output*")
+(defvar py-output-buffer "*Python Output*")
 (make-variable-buffer-local 'py-output-buffer)
 
-;; for toggling between CPython and Jython
-(defvar py-which-shell nil)
-(defvar py-which-args  py-python-command-args)
-(defvar py-which-bufname "Python")
-(make-variable-buffer-local 'py-which-shell)
-(make-variable-buffer-local 'py-which-args)
-(make-variable-buffer-local 'py-which-bufname)
-
 (defun py-toggle-shells (arg)
-  "Toggles between the CPython and Jython shells.
+  "Toggle between the CPython and Jython shells.
 
 With positive argument ARG (interactively \\[universal-argument]),
 uses the CPython shell, with negative ARG uses the Jython shell, and
@@ -1643,13 +1713,15 @@
     (setq comint-prompt-regexp (concat py-shell-input-prompt-1-regexp "\\|"
                                        py-shell-input-prompt-2-regexp "\\|"
                                        "^([Pp]db) "))
-    (add-hook 'comint-output-filter-functions
-	      'py-comint-output-filter-function)
+    (add-hook (make-local-hook 'comint-output-filter-functions)
+	      'py-comint-output-filter-function nil t)
     ;; pdbtrack
-    (add-hook 'comint-output-filter-functions 'py-pdbtrack-track-stack-file)
+    (add-hook 'comint-output-filter-functions 'py-pdbtrack-track-stack-file
+	      nil t)
     (setq py-pdbtrack-do-tracking-p t)
     (set-syntax-table py-mode-syntax-table)
     (use-local-map py-shell-map)
+    (set (make-local-variable 'indent-line-function) 'tab-to-tab-stop)
     (run-hooks 'py-shell-hook)
     ))
 
@@ -1756,7 +1828,7 @@
       (setq py-exception-buffer (cons file (current-buffer))))
      (t
       ;; TBD: a horrible hack, but why create new Custom variables?
-      (let ((cmd (concat py-which-shell (if (string-equal py-which-bufname
+      (let ((cmd (concat shell (if (string-equal py-which-bufname
 							  "Jython")
 					    " -" ""))))
 	;; otherwise either run it synchronously in a subprocess
@@ -1909,19 +1981,20 @@
   "Jump to the code which caused the Python exception at EVENT.
 EVENT is usually a mouse click."
   (interactive "e")
-  (cond
-   ((fboundp 'event-point)
-    ;; XEmacs
-    (let* ((point (event-point event))
-	   (buffer (event-buffer event))
-	   (e (and point buffer (extent-at point buffer 'py-exc-info)))
-	   (info (and e (extent-property e 'py-exc-info))))
+  (if (featurep 'xemacs)		; help Emacs 21.4 compiler.
+      (let* ((point (event-point event))
+	     (buffer (event-buffer event))
+	     (e (and point buffer (extent-at point buffer 'py-exc-info)))
+	     (info (and e (extent-property e 'py-exc-info))))
+	(message "Event point: %d, info: %s" point info)
+	(and info
+	     (py-jump-to-exception (car info) (cdr info))))
+    (let* ((point (posn-point (event-end event)))
+	   (buffer (window-buffer (posn-window event)))
+	   (info (and point buffer (get-char-property e 'py-exc-info))))
       (message "Event point: %d, info: %s" point info)
       (and info
-	   (py-jump-to-exception (car info) (cdr info)))
-      ))
-   ;; Emacs -- Please port this!
-   ))
+	   (py-jump-to-exception (car info) (cdr info))))))
 
 (defun py-goto-exception ()
   "Go to the line indicated by the traceback."
@@ -1956,7 +2029,7 @@
 
 (defun py-down-exception (&optional bottom)
   "Go to the next line down in the traceback.
-With \\[univeral-argument] (programmatically, optional argument
+With \\[universal-argument] (programmatically, optional argument
 BOTTOM), jump to the bottom (innermost) exception in the exception
 stack."
   (interactive "P")
@@ -2034,7 +2107,7 @@
       (if base-found-p
 	  (message "Closes block: %s" base-text)))))
 
-
+;; XEmacs only.
 (defun py-electric-delete (arg)
   "Delete preceding or following character or levels of whitespace.
 
@@ -2048,12 +2121,14 @@
 function in `py-delete-function'.
 
 \\[universal-argument] (programmatically, argument ARG) specifies the
-number of characters to delete (default is 1)."
+number of characters to delete (default is 1).
+
+This function is only used in XEmacs."
   (interactive "*p")
-  (if (or (and (fboundp 'delete-forward-p) ;XEmacs 21
-	       (delete-forward-p))
-	  (and (boundp 'delete-key-deletes-forward) ;XEmacs 20
-	       delete-key-deletes-forward))
+  (if (or (if (fboundp 'delete-forward-p) ;XEmacs 21
+	      (delete-forward-p))
+	  (if (boundp 'delete-key-deletes-forward) ;XEmacs 20
+	      delete-key-deletes-forward))
       (funcall py-delete-function arg)
     (py-electric-backspace arg)))
 
@@ -2071,7 +2146,7 @@
   "Fix the indentation of the current line according to Python rules.
 With \\[universal-argument] (programmatically, the optional argument
 ARG non-nil), ignore dedenting rules for block closing statements
-(e.g. return, raise, break, continue, pass)
+\(e.g. return, raise, break, continue, pass).
 
 This function is normally bound to `indent-line-function' so
 \\[indent-for-tab-command] will call it."
@@ -2418,7 +2493,7 @@
 You cannot dedent the region if any line is already at column zero."
   (interactive
    (let ((p (point))
-	 (m (mark))
+	 (m (if (py-mark-active) (mark)))
 	 (arg current-prefix-arg))
      (if m
 	 (list (min p m) (max p m) arg)
@@ -2446,7 +2521,7 @@
 many columns.  With no active region, indent only the current line."
   (interactive
    (let ((p (point))
-	 (m (mark))
+	 (m (if (py-mark-active) (mark)))
 	 (arg current-prefix-arg))
      (if m
 	 (list (min p m) (max p m) arg)
@@ -2663,7 +2738,10 @@
 	     (looking-at start-re))
 	(end-of-line))
     (if (re-search-backward start-re nil 'move count)
-	(goto-char (match-beginning 0)))))
+	(goto-char (match-beginning 0))))
+  ;; We could be in a string, in which case, try again.
+  (if (nth 8 (parse-partial-sexp (point-min) (point)))
+      (py-beginning-of-def-or-class class count)))
 
 ;; Backwards compatibility
 (defalias 'beginning-of-python-def-or-class 'py-beginning-of-def-or-class)
@@ -2724,7 +2802,7 @@
      ((eq state 'not-found) nil)
      (t (error "Internal error in `py-end-of-def-or-class'")))))
 
-;; Backwards compabitility
+;; Backwards compatibility
 (defalias 'end-of-python-def-or-class 'py-end-of-def-or-class)
 
 
@@ -2843,7 +2921,7 @@
     ;; set mark & display
     (if just-move
 	()				; just return
-      (push-mark (point) 'no-msg)
+      (push-mark (point) 'no-msg t)
       (forward-line -1)
       (message "Mark set after: %s" (py-suck-up-leading-text))
       (goto-char initial-pos))))
@@ -2922,6 +3000,8 @@
   (py-keep-region-active))
 
 ;; ripped from cc-mode
+;; In the distant future, Emacs 23 will have a minor mode for doing
+;; this sort of thing properly.
 (defun py-forward-into-nomenclature (&optional arg)
   "Move forward to end of a nomenclature section or word.
 With \\[universal-argument] (programmatically, optional argument ARG),
@@ -2978,13 +3058,8 @@
 
 
 ;; Pychecker
-
-;; hack for FSF Emacs
-(unless (fboundp 'read-shell-command)
-  (defalias 'read-shell-command 'read-string))
-
 (defun py-pychecker-run (command)
-  "*Run pychecker (default on the file currently visited)."
+  "Run pychecker (default on the file currently visited)."
   (interactive
    (let ((default
            (format "%s %s %s" py-pychecker-command
@@ -3021,11 +3096,13 @@
 ;; separate function.  Note that Emacs doesn't have the original
 ;; function.
 (defun py-symbol-near-point ()
-  "Return the first textual item to the nearest point."
+  "Return the first textual item nearest point."
   ;; alg stolen from etag.el
   (save-excursion
     (with-syntax-table py-dotted-expression-syntax-table
       (if (or (bobp) (not (memq (char-syntax (char-before)) '(?w ?_))))
+	  ;; Fixme: Should it be \\s' below?  We don't have prefix
+	  ;; syntax anyhow.
 	  (while (not (looking-at "\\sw\\|\\s_\\|\\'"))
 	    (forward-char 1)))
       (while (looking-at "\\sw\\|\\s_")
@@ -3043,7 +3120,7 @@
   "Get help from Python based on the symbol nearest point."
   (interactive)
   (let* ((sym (py-symbol-near-point))
-	 (base (substring sym 0 (or (search "." sym :from-end t) 0)))
+	 (base (mapconcat 'identity (butlast (split-string sym "\\.")) "."))
 	 cmd)
     (if (not (equal base ""))
         (setq cmd (concat "import " base "\n")))
@@ -3357,18 +3434,38 @@
 to newline-and-indent in the global keymap, and shadows them with
 local bindings to py-newline-and-indent."))
 
-(require 'info-look)
+(defconst py-python-version
+  (let ((s (shell-command-to-string (concat py-python-command " -V"))))
+    (string-match "^Python \\([0-9]+\\.[0-9]+\\>\\)" s)
+    (match-string 1 s)))
+
 ;; The info-look package does not always provide this function (it
 ;; appears this is the case with XEmacs 21.1)
-(when (fboundp 'info-lookup-maybe-add-help)
-  (info-lookup-maybe-add-help
-   :mode 'python-mode
-   :regexp "[a-zA-Z0-9_]+"
-   :doc-spec '(("(python-lib)Module Index")
-	       ("(python-lib)Class-Exception-Object Index")
-	       ("(python-lib)Function-Method-Variable Index")
-	       ("(python-lib)Miscellaneous Index")))
-  )
+(eval-after-load "info-look"
+  '(when (fboundp 'info-lookup-maybe-add-help)
+     (let* ((version (py-python-version))
+	    (versioned
+	     (save-window-excursion
+	       (condition-case ()
+		   (progn (info (format "(python%s-lib)Miscellaneous Index"
+					version))
+			  (Info-last)
+			  (Info-exit)
+			  t)
+		 (error nil)))))
+       (unless versioned
+	 (setq version ""))
+       (info-lookup-maybe-add-help
+	:mode 'python-mode
+	:regexp "[a-zA-Z0-9_]+"
+	:doc-spec
+	;; Fixme: Add python-ref?  Can this reasonably be made specific
+	;; to indices with different rules?
+	;; `version' is needed for Debian, at least.
+	'((,(concat "(python" version "-lib)Module Index"))
+	  (,(concat "(python" version "-lib)Class-Exception-Object Index"))
+	  (,(concat "(python" version "-lib)Function-Method-Variable Index"))
+	  (,(concat "(python" version "-lib)Miscellaneous Index")))))))
 
 
 ;; Helper functions
@@ -3396,7 +3493,8 @@
 	;; we're in a triple-quoted string or not.  Emacs does not
 	;; have this built-in function, which is its loss because
 	;; without scanning from the beginning of the buffer, there's
-	;; no accurate way to determine this otherwise.
+	;; no accurate way to determine this otherwise. ?? What is this
+	;; better way?
 	(save-excursion (setq pps (parse-partial-sexp (point) here)))
 	;; make sure we don't land inside a triple-quoted string
 	(setq done (or (not (nth 3 pps))
@@ -3440,7 +3538,7 @@
   "Go to the beginning of the triple quoted string we find ourselves in.
 DELIM is the TQS string delimiter character we're searching backwards
 for."
-  (let ((skip (and delim (make-string 1 delim)))
+  (let ((skip (and delim (not (eq delim t)) (make-string 1 delim)))
 	(continue t))
     (when skip
       (save-excursion
@@ -3478,7 +3576,7 @@
   (beginning-of-line))
 
 (defun py-goto-beyond-final-line ()
-  "Go to the point just beyond the fine line of the current statement.
+  "Go to the point just beyond the final line of the current statement.
 Usually this is the start of the next line, but if this is a
 multi-line statement we need to skip over the continuation lines."
   ;; Tricky: Again we need to be clever to avoid quadratic time
@@ -3586,7 +3684,7 @@
       t)))
 
 (defun py-go-up-tree-to-keyword (key)
-  "Go to begining of statement starting with KEY, at or preceding point.
+  "Go to beginning of statement starting with KEY, at or preceding point.
 
 KEY is a regular expression describing a Python keyword.  Skip blank
 lines and non-indenting comments.  If the statement found starts with
@@ -3624,12 +3722,13 @@
 (defun py-suck-up-first-keyword ()
   "Return first keyword on the line as a Lisp symbol.
 `Keyword' is defined (essentially) as the regular expression
-([a-z]+).  Returns nil if none was found."
+\([a-z]+).  Returns nil if none was found."
   (let ((case-fold-search nil))
     (if (looking-at "[ \t]*\\([a-z]+\\)\\>")
 	(intern (buffer-substring (match-beginning 1) (match-end 1)))
       nil)))
 
+;; Fixme: Doesn't DTRT for point in class before first def.
 (defun py-current-defun ()
   "Python value for `add-log-current-defun-function'.
 This tells add-log.el how to find the current function/method/variable."
@@ -3658,7 +3757,7 @@
 	(setq assignment t)
 	(setq sep "."))
 
-      ;; Prepend the name of each outer socpe (def or class).
+      ;; Prepend the name of each outer scope (def or class).
 
       (while (not dead)
 	(if (and (py-go-up-tree-to-keyword "\\(class\\|def\\)")
@@ -3735,7 +3834,6 @@
 
 ;; arrange to kill temp files when Emacs exists
 (add-hook 'kill-emacs-hook 'py-kill-emacs-hook)
-(add-hook 'comint-output-filter-functions 'py-pdbtrack-track-stack-file)
 
 ;; Add a designator to the minor mode strings
 (or (assq 'py-pdbtrack-is-tracking-p minor-mode-alist)
@@ -3748,7 +3846,7 @@
 ;;; see http://mail.python.org/pipermail/python-list/2002-May/103189.html
 
 (defun py-fill-comment (&optional justify)
-  "Fill the comment paragraph around point"
+  "Fill the comment paragraph around point."
   (let (;; Non-nil if the current line contains a comment.
 	has-comment
 
@@ -3813,7 +3911,7 @@
 
 
 (defun py-fill-string (start &optional justify)
-  "Fill the paragraph around (point) in the string starting at start"
+  "Fill the paragraph around point in the string starting at start."
   ;; basic strategy: narrow to the string and call the default
   ;; implementation
   (let (;; the start of the string's contents
@@ -3874,8 +3972,7 @@
 If any of the current line is a comment, fill the comment or the
 paragraph of it that point is in, preserving the comment's indentation
 and initial `#'s.
-If point is inside a string, narrow to that string and fill.
-"
+If point is inside a string, narrow to that string and fill."
   (interactive "P")
   (let* ((bod (py-point 'bod))
 	 (pps (parse-partial-sexp bod (point))))
@@ -3904,7 +4001,18 @@
      (t
       (fill-paragraph justify)))))
 
+
+(mapcar (lambda (m)
+	  (add-to-list 'debug-ignored-errors m))
+	'("Not on a traceback line"
+	  " of traceback$"
+	  "Sorry, couldn't guess a value for py-indent-offset"
+	  "Region is at left edge"
+	  "Bad indentation in region, at line"
+	  "Enclosing block not found"))
 
+(defun python-mode-unload-hook ()
+  (remove-hook 'kill-emacs-hook 'py-kill-emacs-hook))
 
 (provide 'python-mode)
 ;;; python-mode.el ends here
