Showing posts with label debugging. Show all posts
Showing posts with label debugging. Show all posts

Saturday, January 20, 2007

IronPython and Traceback line numbers in Mono (workaround)

One of the reasons why I need to have access to a Windows dev environment when doing my IronPython/Mono development is the lack of line numbers in IronPython tracebacks under Mono. But via Seo Sanghyeon comes a workround. He has discovered that that Mono can't display line numbers from AssemblyBuilder built in memory, but only from Assembly loaded from disk. So you need run mono in debug mode and get IronPython to compile and save the assemblies to disk. So if we have a buggy script like:

a = 1
b = 0
c = a/b

Prior to the workround the traceback would have been:

Traceback (most recent call last):
File foo, line unknown, in Initialize
ZeroDivisionError: Division by zero

But if I start IronPython using:

mono --debug ipy.exe -X:SaveAssemblies foo.py

you get a more helpful traceback

Traceback (most recent call last):
File /u1/ip/IPCE/IPCE-svn/Lib/site.py, line 33, in Initialize
File /u1/ip/IPCE/IPCE-svn/Lib/fepy/__init__.py, line 7, in install
File /u1/ip/IPCE/IPCE-svn/Lib/fepy/__init__.py, line 11, in install_option
File /u1/ip/IPCE/IPCE-svn/Lib/fepy/ast.py, line 17, in Initialize
SystemError: Object reference not set to an instance of an object
Traceback (most recent call last):
File /tmp/foo.py, line 3, in Initialize
ZeroDivisionError: Division by zero

Thanks again Sangyheon.

Thursday, November 23, 2006

IronPython and trace style debugging

When developing with IronPython under Windows, there is excellent debugger support via Visual Studio. But sometimes you just want to do simple trace style debugging, in other words, put some print statements in your code. This works well when developing an application you can run under the console but is problematic if the application is a service or ASP.NET handler. When developing similar applications with CPython under Windows, I used the win32trace.pyd/win32traceutil.py to achieve this.

From the win32 python docs:

These modules allow one Python process to generate output via a "print" statement, and another unrelated Python process to display the data. This works even if the Python process generating the output is running under the context of a service, where more traditional means are not available. The module works on Windows 95 and Windows NT.

To enable this debugging, simply "import win32traceutil" somewhere in your program - thats it! This automatically re-directs the standard Python output streams to the remote collector (If that behaviour is undesirable, you will need to use win32trace directly.) To actually see the output as it is produced, start a DOS prompt, and run the file "win32traceutil.py" (eg, double-click on it from Explorer, or "python.exe win32traceutil.py") This will print all output from all other Python processes (that have imported win32traceutil) until you kill it with Ctrl+Break!)



So I decided you create something similar for IronPython. win32trace uses a memory mapped file for communication between the application and the trace collector. Since the only way I could find to use memory mapped files under CLI, relied on calls to unmanaged win32 api, I decided to use network UDP datagrams instead. Rather than writing something from scratch, I remembered a python script that I had used many years ago, creosote.py by Jeff Bauer. The original link to the script is broken, so I finally tracked a copy down in the Zope CVS. So I wrapped this code in a wrapper traceutil.py.

To use it, you just need to put this script in your IronPython or CPython path, and any output to stdout or stderr will be sent to the collector.

To start the collector:

ipy.exe traceutil.py


If the following code is run as a script by IronPython or CPython:

import traceutil

print "start"
a = "A"
# Create an error
import monty


the following would appear in the collector console running under .NET:

creosote bucket waiting on port: 7739
start
\n
Traceback (most recent call last):\r\n File E:\\IronPython\\IPCE-r4\\test_traceutil.py, line 6, in Initialize\r\n File , line 0, in __import__##4r\nImportErr
or: No module named monty\r\n


and the following would appear in the collector console running under Mono:

creosote bucket waiting on port: 7739
start
\n
Traceback (most recent call last):\n File test, line unknown, in Initialize\nImportError: No module named monty\n

It is important to note that the creosote client code does not block if the collector isn't running which is a good behaviour.