Perhaps I am missing some basic technique, but I don't believe this is documented anywhere, including the numerous debugging how-to's I've read. First, this simple technique for debugging Zope & Zope products within emacs amounts to: 1) Make some simple changes to emacs configs 2) Make some simple changes to Zope so that it handles requests single threaded 3) Specify where in the Zope (or your) code the debugger should start 4) Run pdb-mode in emacs, telling it to start Zope I don't think Test.py cuts it for me because I want to be able to see the response in a browser, and I like to interact with the dugger in an IDE (for me, emacs). The big problem was that the default PubCore behavior involves a separate thread which handles the request, and this wreaks havoc on pdb & on emacs' comint mode. The details have to do with the fact that pdb does not track thread creation & switching, etc. So, now the details: 1) Make some simple changes to emacs configs 1.A) I assume you're running the latest emacs with decently current python & gud modes. 1.B) Put this into your .emacs if you're running on win32: (setq gud-pdb-marker-regexp "^> \\([-a-zA-Z0-9_/.:\\]*\\|<string>\\)(\\([0-9]+\\))\\([a-zA-Z0-9_]*\\|\\?\\)( )\\(->[^\n]*\\)?\n") 2) Make some simple changes to Zope so that it handles requests single threaded This amounts to replacing the contents of __init__.py in PubCore with the lines following the ============= at the bottom of this message 3) Specify where in the Zope (or your) code the debugger should start Put import pdb at the very top of one of the Zope product files, even at the top of z2.py and pdb.set_trace() at the spot you want to start debugging from. I bet with some name space trickery you can make this happen inside a DTML document. Haven't tried yet. 4) Run pdb-mode in emacs, telling it to start Zope M-x pdb enter the following as the command, assuming a win32 platform and my setup: D:\Zope\bin\python.exe -i D:\Zope\z2.py -D -t 1 When your set_trace() call gets hit, you will be dropped into the debugger, and emacs will load the right file and move around with you as you use debugging commands. Enter "continue" and Zope will go along its merry way and return the results of your page to the browser, and wait for the next request. I hope this saves someone the 2 hours of reading Zope, medusa, and other sources that I spent. If this is totally misguided and there is a simpler technique, I'm all ears!! A. =================== import ZRendezvous from ZPublisher import publish_module _handle=None _n=1 def _simple_handle(name,request,response): print name,request,response try: publish_module( name, request=request, response=response) finally: response._finish() def handle(*args, **kw): global _handle global _n if _handle is None: if _n==1: _handle = _simple_handle else: _handle=ZRendezvous.ZRendevous(_n).handle return apply(_handle, args, kw) def setNumberOfThreads(n): global _n _n=n global setNumberOfThreads del setNumberOfThreads