7

When writing literate Python with Org–Babel, I need to be able to control the indentation level (either explicitly with :indentation-level 3 or implicitly with some clever indication).

Here's an example file that demonstrates the problem.

#+BEGIN_SRC python :tangle "sample.py"
  class Test:
      def __init__(self):
          self.a = 'a test class'
#+END_SRC
#+BEGIN_SRC python :tangle "sample.py"
      def say_hi(self):
          print 'Hi from this Test object!'
          print 'ID: {}'.format(repr(self))
          print 'Data: {}'.format(str(self.__dict__))
#+END_SRC
Sean Allred
  • 3,558
  • 3
  • 32
  • 71
  • Hm, org-babel respects the indentation of the programming mode. If you edit the code snippet with `C-'` you can change the indentation with `C-c >` from `python-mode`. But, I guess this is not what you want. What is the reason for the wanted option `:indentation-level`? – Tobias Jan 03 '14 at 04:09
  • @Tobias When I `org-babel-tangle` the file, indentation is not respected given a whitespace prefix with the `#+begin_src` environment. Everything is alright if I keep it all in one source block, but good sense says to split it up and explain each part. – Sean Allred Jan 03 '14 at 04:45
  • But, this works for me! All indentation is copied verbatim from the org file. – Tobias Jan 03 '14 at 06:12
  • @Tobias How strange… I will upload a video to prove I'm not crazy XD – Sean Allred Jan 03 '14 at 06:39
  • @Tobias Org version 8.2.4: http://www.youtube.com/watch?v=T0gGW3T4zRo (warning: my keyboard is a little loud) – Sean Allred Jan 03 '14 at 07:53
  • Sorry that you had to go through this. After your video I re-started `emacs` with `-q` and recognized what you mean. The solution is in the answer. – Tobias Jan 03 '14 at 11:51
  • @Tobias I just updated emacs for a new machine so I'll re-test your answer. Just as a record for what I did in the meantime, using noweb references solves the issue in practice. – Sean Allred Feb 26 '14 at 17:19

3 Answers3

9

Set org-src-preserve-indentation to t.

Tobias
  • 5,038
  • 1
  • 18
  • 39
  • It seems that, even with this set, the first line is still indented poorly: http://i.stack.imgur.com/0EwwH.png – Sean Allred Jan 03 '14 at 19:23
  • 1
    Well, this does work, but an annoying side-effect is that all the code blocks (not only python) become left justified. Is there a way to avoid this, or at least to restrict this option only to python source blocks? Thanks. – Ajned Sep 12 '20 at 06:48
4

I didn't perfectly like Tobias' answer because when I org-edit-special (C-c ') a code block, my python-mode buffer would yell at me (I have several python minor modes with syntax checkers) because of the unexpected indent for blocks with stand-alone methods (because with org-src-preserve-indentation set, I would have indents in front of all my methods in their individual blocks). So instead, I like this solution using org-mode's :noweb header argument:

#+BEGIN_SRC python :tangle "sample.py" :noweb yes
  class Test:
      <<init_method>> # these are indented
      <<more_methods>> # these are indented
#+END_SRC

#+BEGIN_SRC python :noweb-ref init_method
  def __init__(self):
      self.a = 'a test class'
#+END_SRC

#+BEGIN_SRC python :noweb-ref more_methods
  def say_hi(self):
      print 'Hi from this Test object!'
      print 'ID: {}'.format(repr(self))
      print 'Data: {}'.format(str(self.__dict__))
#+END_SRC

As long as you just indent the Noweb syntax references (the double << >>) in your class definition, the other blocks ("init_method" and "more_methods") will be tangled with respect to your indentation. So, the final output "sample.py" file looks like this:

class Test:
    def __init__(self):
        self.a = 'a test class'
    def say_hi(self):
        print 'Hi from this Test object!'
        print 'ID: {}'.format(repr(self))
        print 'Data: {}'.format(str(self.__dict__))

Nice!

coltoneakins
  • 849
  • 6
  • 14
1

I know it is not the desired solution but as a work around you can insert a comment (specific to your programming language) in the source block and make the desired indentation after that comment. This will also preserve the indentation when exiting the edit-buffer

#+BEGIN_SRC python :tangle "sample.py"
  class Test:
      def __init__(self):
          self.a = 'a test class'
#+END_SRC
#+BEGIN_SRC python :tangle "sample.py"
  # This is my dummy python comment to keep the correct indentation 
      def say_hi(self):
          print 'Hi from this Test object!'
          print 'ID: {}'.format(repr(self))
          print 'Data: {}'.format(str(self.__dict__))
#+END_SRC
Markus
  • 11
  • 1