2
votes

This has been an exquisite exercise in frustration. For some reason, my python-mode / elpy buffers always have intent-tabs-mode nil. I'm using python-mode 6.2.3, elpy 1.32.0, and emacs 25.2.2. My .emacs file contains:

;; =============================================================================
;; Trying to get indentation to be tabs of width 4 spaces in Python is a real
;; pain. For some unknown reason, unlike EVERY other progmode file in the distro
;; python.el contains this gem:
;;
;;     5480: (set (make-local-variable 'tab-width) 8)
;;
;; which clobbers any defaults you might have, no questoins asked. It also has
;; this wonderful nugget:
;;
;;     5481: (set (make-local-variable 'indent-tabs-mode) nil)
;;
;; Because someone wants to force using spaces (so wby bother forcing
;; tab-width?)
;; -----------------------------------------------------------------------------
;; Do this first. Because of the above, if you don't python.el will clobber
;; your attempts to customize this stuff.
(load "python-mode")
;; Now follow the instructions sprinked all over the Interwebs by the thousands
;; of people frustrated by the above clobbering.
(add-hook 'python-mode-hook
      ;; Don't forget lambda(), God forbid
      (lambda ()
        ;; Now set the tab-width you really want here and cross your fingers
        (setq tab-width 4)
        ;; And tell python-mode to use tabs. I know lots of folks hate on
        ;; tabs, but whatever.
        (setq indent-tabs-mode t)
        ;; If you want to make sure you don't have trailing whitespaces
        ;; at the end of line, uncomment this.
        ;;(add-to-list 'write-file-functions 'delete-trailing-whitespace)
        )
      )

But indent-tabs-mode remains nil. Only in python-mode, of course. From describe-variable from within a python-mode / elpy buffer:

indent-tabs-mode is a variable defined in ‘C source code’.
Its value is nil
Original value was t
Local in buffer config; global value is t

  Automatically becomes buffer-local when set.
  This variable is safe as a file local variable if its value
  satisfies the predicate ‘booleanp’.

Documentation:
Indentation can insert tabs if this is non-nil.

You can customize this variable.

The version I'm using of python-mode.el contains the following [lines 955-964]:

  "Python-mode starts `indent-tabs-mode' with the value specified here, default is nil. "
  :type 'boolean
  :tag "py-indent-tabs-mode"
  :group 'python-mode)

[lines 5159-5165]

       ["indent-tabs-mode"
        (setq indent-tabs-mode
          (not indent-tabs-mode))
        :help "Indentation can insert tabs if this is non-nil.

Use `M-x customize-variable' to set it permanently"
        :style toggle :selected indent-tabs-mode]

[lines 6787-6820]

(defun py-toggle-indent-tabs-mode ()
  "Toggle `indent-tabs-mode'.

Returns value of `indent-tabs-mode' switched to. "
  (interactive)
  (when
      (setq indent-tabs-mode (not indent-tabs-mode))
    (setq tab-width py-indent-offset))
  (when (and py-verbose-p (called-interactively-p 'any)) (message "indent-tabs-mode %s  py-indent-offset %s" indent-tabs-mode py-indent-offset))
  indent-tabs-mode)

(defun py-indent-tabs-mode (arg &optional iact)
  "With positive ARG switch `indent-tabs-mode' on.

With negative ARG switch `indent-tabs-mode' off.
Returns value of `indent-tabs-mode' switched to. "
  (interactive "p")
  (if (< 0 arg)
      (progn
        (setq indent-tabs-mode t)
        (setq tab-width py-indent-offset))
    (setq indent-tabs-mode nil))
  (when (and py-verbose-p (or iact (called-interactively-p 'any))) (message "indent-tabs-mode %s   py-indent-offset %s" indent-tabs-mode py-indent-offset))
  indent-tabs-mode)

(defun py-indent-tabs-mode-on (arg)
  "Switch `indent-tabs-mode' on. "
  (interactive "p")
  (py-indent-tabs-mode (abs arg)(called-interactively-p 'any)))

(defun py-indent-tabs-mode-off (arg)
  "Switch `indent-tabs-mode' off. "
  (interactive "p")
  (py-indent-tabs-mode (- (abs arg))(called-interactively-p 'any)))

[lines 22259-22266]

;;  unconditional Hooks
;;  (orgstruct-mode 1)
(add-hook 'python-mode-hook
      (lambda ()
        (setq imenu-create-index-function py--imenu-create-index-function)
        (setq indent-tabs-mode py-indent-tabs-mode)))

(remove-hook 'python-mode-hook 'python-setup-brm)

And again (almost identical from above) [lines 25021-25033]:

          ["indent-tabs-mode"
           (setq indent-tabs-mode
             (not indent-tabs-mode))
           :help "Indentation can insert tabs if this is non-nil.

Use `M-x customize-variable' to set it permanently"
           :style toggle :selected indent-tabs-mode]

          ["Tab indent"
           (setq py-tab-indent
             (not py-tab-indent))
           :help "Non-nil means TAB in Python mode calls `py-indent-line'.Use `M-x customize-variable' to set it permanently"
           :style toggle :selected py-tab-indent]

I have set every single version of any definition I could find in any *.el file of indent-tabs-mode to t and nothing works.

1
You clearly already knew the answer to your “question”, since you posted both of them at the same time.donkopotamus
@donkopotamus: there is nothing wrong with that. If the question arises often, then people will find the answer here and be grateful for it (if the answer is correct of course). If the question does not arise often, then nobody will upvote either the question or the answer, so the OP will perhaps have wasted a bit of time writing it up, but that's no skin off anybody's nose (except perhaps the OP's).NickD

1 Answers

2
votes

Turns out, for some versions of python.el, you need to add (yay!) yet another item. This worked, finally:

;; =============================================================================
;; Trying to get indentation to be tabs of width 4 spaces in Python is a real
;; pain. For some unknown reason, unlike EVERY other progmode file in the distro
;; python.el contains this gem:
;;
;;     5480: (set (make-local-variable 'tab-width) 8)
;;
;; which clobbers any defaults you might have, no questoins asked. It also has
;; this wonderful nugget:
;;
;;     5481: (set (make-local-variable 'indent-tabs-mode) nil)
;;
;; Because someone wants to force using spaces (so wby bother forcing
;; tab-width?)
;; -----------------------------------------------------------------------------
;; Do this first. Because of the above, if you don't python.el will clobber
;; your attempts to customize this stuff.
(load "python-mode")
;; Now follow the instructions sprinked all over the Interwebs by the thousands
;; of people frustrated by the above clobbering.
(add-hook 'python-mode-hook
      ;; Don't forget lambda(), God forbid
      (lambda ()
        ;; Now set the tab-width you really want here and cross your fingers
        (setq tab-width 4)
        ;; And tell python-mode to use tabs. I know lots of folks hate on
        ;; tabs, but whatever.
        (setq indent-tabs-mode t)
        ;; Some verions of python.el use this, others don't
        (setq py-indent-tabs-mode t)
        ;; If you want to make sure you don't have trailing whitespaces
        ;; at the end of line, uncomment this.
        ;;(add-to-list 'write-file-functions 'delete-trailing-whitespace)
        )
      )