Tuesday, June 26, 2007

python in emacs

Writing/Debugging Python in Emacs

Posted by icottee on 2004년 7월 1일 목요일

Having noted about getting IDLE running for Debugging Zope I thought again about the stuff I use with Emacs for writing Python/Zope stuff. There's quite a lot out there which gives you a lot of power for both writing and debugging and try as I might I just can't get to like the commercial Python IDE stuff out - mostly because it is not Emacs. So this little article explains about
  • Python Mode
  • PDB (Python Debugger) and integration with Emacs
  • Else - A language templating system
I am a GNU Emacs user but a lot of this will be relevant no doubt to XEmacs. Leave some comments if I need to make some ammendments. I am not an expert pythonist or an expert Emacs user. This is just a place to note what I use and how I use it. At the moment this is not a finished document either. There's a few more things I want to add in the near future. 2> Python mode is a major mode for emacs which makes writing Python software easier. From memory I think Python mode comes with most modern Emacs these days but I could be wrong. Regardless I tend to download the latest version from the Python-Mode Sourceforge Site.

Setting up Python Mode

I'm not going to turn this into an emacs tutorial but for most of my added extra I tend to stick them in a directory called ~/emacs-stuff/lisp and then in my .emacs I have:
(setq load-path (cons "~/emacs-stuff/lisp" load-path))
as my very first line. There's an amount of other stuff you'll be needing in your .emacs as well. Like most people my .emacs has grown over time and it's possible that some of this is cruft. But for the record the Python specific stuff in my .emacs is as follows. I've commented what this stuff does (or what I think it does) in the lisp comments.
;; Associate .py files with python mode
(setq auto-mode-alist
(cons '(".py$" . python-mode) auto-mode-alist))

;; Use the 'python' interpreter when executing code in python-mode.
;; You might want to change this if you have a number of pythons on your
;; path but want to use a specific version (e.g. python2.3)
(setq interpreter-mode-alist
(cons '("python" . python-mode)
interpreter-mode-alist))

;; These are various settings you may want to set
;; -- py-indent-offset - the number of spaces you are going to indent by
;; -- py-smart-indentation - this allows emacs to guess what your indentation
;; should be. I set it to nil because I don't want it to do that. I religiously
;; believe everything should be 4 spaces ;)
;; -- indent-tabs-mode - set to nil - tabs are evil. We indent with spaces
;;
(setq python-mode-hook
'(lambda () (progn
(set-variable 'py-indent-offset 4)
(set-variable 'py-smart-indentation nil)
(set-variable 'indent-tabs-mode nil) )))

;; If you start a shell up within python-mode using 'py-shell' this is the
;; interpreter you are going to be using
(defconst py-python-command "python")

;; Load the code in
(autoload 'python-mode "python-mode" "Python editing mode." t)
There are of course many other settings that can be made. python-mode.el is very well commented so read through that to get an idea for what else you can do.

Using Python Mode

Assuming you have python mode running (quit out of emacs and restart it if you want to make sure everything is loaded after your .emacs changes) you can now edit a python file. Create a new file (call it anything, just make sure it ends with .py) and you should find python mode is loaded automatically. In your status bar you'll see the word 'Python' signifying you are in the python major mode. Big fat hairy deal. So what can you do. Lets write a little test python script.
class cheese :
def __init__ (self, colour, strength) :
self.colour = colour
self.strength = strength

def __str__(self):
return 'This is some %s, %s cheese' % (self.colour, self.strength)

if __name__ == '__main__':
cheddar = cheese('yellow', 'strong')
print cheddar
You'll find as you type this in that emacs automatically handles the indentation for you. You can go back one level by pressing the backspace key at the beginning of a line. You can indent a region of code by type 'Ctl-c >' or unintend by using 'Ctl-c < '. You can comment out a region of python code by selecting it and doing 'Ctl-c #'. By default there is no keystroke bound to the uncomment function but you can find it in the Python Menu. There are other function there as well and you can get a complete list of all the py commands by typing Meta-X(return)py-(tab). Once again the source code is your friend. Most of the time though you are going to be editing code and running it. Running code is nice and simple. Ctl-c Ctl-c will run the python code in the current buffer and send any output to a buffer called *Python Output*. If that buffer already exists it will send it to wherever it is currently located. If the buffer does not exist it will create it. Usually when I am developing I will split the screen into half vertically (depends on your screen size of course), use the left panel for my main editing and then divide the right screen into smaller sections with my python output window at the bottom. Ctl-x 3 splits the windows vertically, Ctl-x 2 splits them horizontally. I'll leave the windows in that state through my whole developing session. Sometimes changing which code is displaying in the main left frame and visiting other files in the right hand frames. You can view an image of what I mean here Although in our current example we only have a very small python file to work with you should note that Python Mode will keep track of all the Python classes and functions open in your source file. They are accessible from the IM-Python menu bar. Use the rescan option to update this list as your code is developed.

Debugging Python with Emacs

I can quite happily write Python code in Emacs and did for a long time. What I didn't do was take advantage of the debugging features that Python/Emacs provides. Lets take a look at what we can do. Before we do anything we want to tweak the default Python Debugger (PDB) behaviour when called from Emacs. To do that here's another piece of code you should add to your .emacs file (Mine is located straight after the last section I gave you). This is written by Kevin Rodgers - see this posting.
(defadvice pdb (before gud-query-cmdline activate)
"Provide a better default command line when called interactively."
(interactive
(list (gud-query-cmdline '/usr/lib/python2.3/pdb.py
(file-name-nondirectory buffer-file-name)))))
Note the path in there - you should try locating your pdb.py for the location of yours. e.g.
find / -name pdb.py -print
or something similar. When you find it you'll need to make pdb.py executable. I do
chmod +x /usr/lib/python2.3/pdb.py
OK - PDB found, made executable, .emacs updated, lets do some debugging. Lets assume you are still editing your cheese script. We can debug this purely by executing the 'pdb' command in emacs. Meta-x pdb (return). You'll now find yourself inside the pdb debugger inside Emacs. This may not sound that exciting but if you start to step through the code you'll find that as you step through it the source code file follows the stepping through with a small pointer in the left margin. Organise your debugging environment and it's quite pleasent to step through code especially when it starts pulling in the python libraries etc. Here is another simple screenshot of what you can expect to see. Note the little arrow on the left hand pane pointing to the current execution point. There's little point in my giving a pdb tutorial here. Much better pythonists than I have done so - have a google. But I will make a few comments here. If you want to use pdb.set_trace() then I still have to launch the script with pdb. I have seen comments from others that this should not be the case but I'm not that fussed about it either way. Just start pdb. Press 'c' for continue and it will continue to execute until it hits your trace statement. As an aside I would like it to drop me into pdb when it hits an exception (when starting within pdb). If anybody can tell me how to do that I'd appreciate it :).

Else

I like Else a lot as for me it gives me a liftoff when starting a project, the home page can be found here. From the website - and I quote:
ELSE is a minor mode for Emacs and will co-exist with any major mode. As such ELSE is intended to offer language sensitive editing support for the current buffer and can thus be used to generate code in several different languages during the same edit session. Use of ELSE is not restricted to use with programming languages, it can be used in any editing situation that requires the entry of information into a form like structure (that's all coding is, after all :-)). Examples are program language constructs, project file headers, project function/procedure headers etc.
. Once again lets run through installing it and then I'll show you how I use it. From the ELSE site you will need at least
  • else-mode.el
  • Python.lse
  • Python-cust.lse In my ~/emacs-stuff/lisp directory I have a subdirectory called else where I put those files. Then in my .emacs file I add the following. At the top I have
    (setq load-path (cons "~/emacs-stuff/lisp/else" load-path))
    and then further on (just after my python stuff actually)
    (require 'else-mode)
    (global-set-key "C-xp" 'else-mode)
    Unfortunately before you are ready to go you are going to need to make some changes. From memory (it was a long time ago) I changed the Python-cust.lse file and amended the INDENT_SIZE to be 4. It's possible I may have made some other changes but I don't remember what they are now :). If you try this and come across other customisations please let me know and I'll add them here. Or if you get stuck mail me at (ian@cottee.org and I can send you my amended templates. Assuming everything is installed, .emacs amended and reloaded and everything is looking good lets produce a new python file. Done that? Good. eh. Nothing interesting happened? Don't panic. Now do Ctl-x p. All that happens is that at the top of your empty file you see
    {compilation_unit}
    Very deep. Now type Ctl-c / e (which is ELSE speak for expand a place holder) and you will see
    {file_header}
    """[text]..."""
    [import_stmt]...
    {statement}...
    [test_statement]
    That's an ELSE template for a python file. A file header, a document string, some import statements, other statements and a test statement. Put your cursor over the test_statement and do Ctl-c /e again and you will now see.
    if __name__ == '__main__':
    {statement}...
    And now if you do the same command sequence over the {statement} you'll get a whole list of valid python statements. Press 'q' to get out of that list without choosing anything. Basically anything surrounded by '[]' or '{}' are place holders that can be expanded. Choosing an option when you expand will often leave you with a skeleton template for the choosen option. Move your cursor to the {statement} above the test statement. Expand it and choose {classdef}. ELSE now gives you the skeleton for the class definition.
    class {classname} [inheritance] :
    [init_def]

    [class_funcdef]...
    All well and good but there's more. Assuming your cursor is currently at the beginning of the class definition type Ctl-c / n (move to next place holder). Your cursor will now be on the classname. You can just type your class name here and then do Ctl-c / n again (note that ELSE cleans out the brackets for you). Your cursor will now be over the inheritance section. You have a number of options here:
  • Ctl-c / k - kills the placeholder (we aren't inheriting anything)
  • Type in a class name to inherit from (inheritting from one class)
  • Type Ctl-c / e - expand the placeholders and allow for multiple inheritance OK - it may seem a bit overwhelming at first but stick with it because it gives you a lot of structure. You can tell when I am using ELSE because there are comment holders everywhere. And although I am not religiously fill them out I certainly comment a lot more when they are there. If what I've written about else sounds interesting then read the fuller documentation on it's home page.

    Conclusion

    OK - that's about enough for now I think. I'll be updating this article again shortly but I hope I've given some basic info on how you can use Emacs with python and the software that is around to help you.
  • 0 Comments:

    Post a Comment

    << Home