Using IronPython with Mono

What Is Mono?

Mono ( is a run time along the same lines as the .NET Framework, and it includes much of the functionality of the .NET Framework. In fact, with each release, Mono gets a bit closer to .NET Framework functionality. However, don’t get the idea that Mono will ever exactly match the .NET Framework. Platform differences, Microsoft copyrights, and other issues will always keep Mono just a bit different from the .NET Framework. Even so, Mono can run a considerable number of .NET applications. The following sections describe Mono, its advantages and limitations, in greater detail.

An Overview of the Mono Family

You can obtain Mono for a considerable number of platforms. In fact, the makers of Mono add new platforms with every release. At one time, Mono worked on just a few Linux implementations, Windows, and the Mac OS X. Over time, Mono support has increased to the exciting list of platforms that follows.

  • LiveCD: This is actually an openSUSE 11.2.1 ( LiveCD (a CD or DVD that contains a bootable image — see Live_CD for details) that includes Mono 2.6.1.
  • Mac OS X: You can use this installation on a number of Mac versions including Mac OS X Tiger (10.4), Leopard (10.5), and Snow Leopard (10.6) (it may work on other versions as well, but you’re on your own for support). The download includes Mono, Cocoa#, and Gtk# (GIMP Toolkit Sharp). You need to download the Client Software Development Kit (CSDK), available on the Mono site, separately. There are separate downloads for the Intel and PowerPC platforms. You can learn more about Mac OS X at
  • openSUSE: You can use this download for the openSUSE 11.0, 11.1, and 11.2 platforms. You must have your own system with openSUSE installed to use it. You can download openSUSE at Just in case you’re interested, the SUSE part of the name stands for Software und System-Entwicklung, which translates to software and systems development.
  • SLES/SLED: You can use this download for SUSE Linux Enterprise Server (SLES) or SUSE Linux Enterprise Desktop (SLED). SLES and SLED are the paid versions of SUSE from Novell. As with openSUSE, you must have your own system with SLES or SLED installed to use this version of Mono. You can find out more about SLES and SLED at
  • Virtual PC: This is actually an openSUSE 11.2.1 virtual PC image that includes Mono 2.6.1. You could use this download to check out Linux functionality for your IronPython application on your PC without leaving Windows. Of course, performance won’t be very good, but it will get the job done.
  • VMware: This is actually an openSUSE 11.2.1 VMware image that includes Mono 2.6.1. You’d use it to check your application for Linux functionality without leaving the host operating system.
  • Windows: You can officially use this download for Windows 2000, XP, 2003, and Vista. Testing shows that it also works fine for Windows 7 and Windows Server 2008. The download includes Mono for Windows, Gtk# (a graphics library to display a user interface onscreen), and XSP (eXtensible Server Pages, an alternate Web server for serving ASP.NET pages). You can also get the Mono Migration Analyzer tool as a separate download.
  • Other: This is a group of less supported platforms including Debian and Ubuntu. At least these two platforms have supported packages. You can also get Mono in an unsupported form for Solaris, Nokia, and Maemo. Theoretically, you could support yet other platforms by compiling the source code found at

Of course, this list contains only a summary of the main Mono downloads. There are a large number of Mono add-ons a well. For example, you can obtain Mono Tools for Visual Studio (http:// if you want to work with Mono directly from Visual Studio. Unfortunately, the current version of this product only works with Visual Studio 2008. The developer should provide a Visual Studio 2010 version soon. You can obtain a trial version of Mono Tools for Visual Studio (registration is required), but you must pay for the full version.

IronPython does include support for Silverlight development. If you plan to use IronPython for Web applications and need to support multiple platforms, you might want to look at Moonlight (http:// instead. This Silverlight replacement works on the same platforms that Mono does and should also work fine with IronPython.

Some of the extensions to Mono are well outside the scope of this book, but are interesting to contemplate. For example, you can get Mono Touch ( to develop applications for the iPhone and iPod Touch devices. The point is that you can probably find some form of Mono to meet just about any need, but using Mono fully means learning some new techniques, such as creating user interfaces using Gtk#.

Considering the Reasons for Using Mono

You already know the reasons that you’re using the .NET Framework and this chapter isn’t about changing your mind. The .NET Framework is stable and many developers love the functionality it provides them for building great applications. However, you could think of Mono as another tool to extend the range of your applications. If for no other reason, the fact that you could run your IronPython application on Linux or the Mac OS X makes Mono a good choice for some forms of application development. In sum, the main reason for using Mono in place of the .NET Framework is flexibility.

As previously mentioned, Mono and the .NET Framework aren’t precisely the same. The first thought that most developers will have is that compatibility issues will be bad, and to a certain extent, they do cause problems. However, Mono also provides functionality that you won’t find when working with the .NET Framework. Features such as Gtk# actually make Mono a better product. In addition, with Mono you have a lightweight Web server for ASP.NET pages, XSP, that works on every Mono platform. Therefore, the differences between Mono and the .NET Framework aren’t always bad — sometimes they become downright useful.

Mono does provide direct support for IronPython, but you need to use a newer version of Mono (see for details). The support isn’t all that good. The section “Running the Application from the Command Line” later in this chapter demonstrates the problem of using the Mono implementation of IronPython. Even so, you do get IronPython support that will likely improve as Mono improves, so this is an area where you can expect Mono to grow as an IronPython platform. In reality, the Mono community is quite excited about IronPython. You can find tutorials for using IronPython in a Mono environment at ironpythontutorial/. If you want to see IronPython running under Mono on a Linux system, see the screenshot and description at

Understanding Mono Limitations

Don’t get the idea that every .NET application will instantly run on Mono. For example, while Mono includes support for Language Integrated Query (LINQ), the support isn’t perfect. The LINQ to SQL support works fine for many applications, but not all of them. The Mono developers realize that the support isn’t complete and they plan to work on it (see the release notes at http://www.mono-project .com/Release_Notes_Mono_2.6.1 for details).

There are some obvious limitations for using Mono that should come to mind immediately. Because the purpose of Mono is to work across platforms, the P/Invoke calls in your extensions aren’t going to work. A P/Invoke call causes your extension to provide Windows-specific support, so using it on Linux wouldn’t work no matter what product you tried. The previous chapters in the book have emphasized when a particular technique is unlikely to produce useful cross-platform results.

The current version of Mono doesn’t work with .NET Framework 4.0 applications. The applications won’t start at all — you see an error message instead. However, Mono does work fine with older versions of the .NET Framework. It’s only a matter of time before Mono supports the .NET Framework 4.0, so this is a short-term limitation that you can easily overcome by using an older version of the .NET Framework when building your application. Given that IronPython doesn’t currently support the .NET Framework 4.0 in many respects, this particular problem isn’t much of an issue for IronPython developers.

In a few cases, you have to look around to determine whether you’ll encounter problems using Mono for a particular task. For example, if your ASP.NET application uses Web Parts, you can’t use Mono (see You also can’t use a precompiled updateable Web site.

Using Mono on Windows Server 2008 Server Core

Early versions of Windows Server 2008 Server Core (Server Core for short) don’t come with any form of the .NET Framework. Consequently, you can’t run any form of .NET application on early versions of Server Core unless you use Mono. The lack of .NET Framework support on Server Core led some people to come up with odd solutions to problems, such as running PowerShell (see the solution at

Fortunately, Microsoft decided to provide a limited version of the .NET Framework for Windows Server 2008 Server Core Edition R2. You can read about it at library/dd883268.aspx. However, this version of the .NET Framework still has significant limitations and you might actually find it better to use Mono for your .NET applications. For example, while you can now provide limited support for ASP.NET on Server Core, you might actually find the Mono alternative, XSP, to provide the solutions you need for your application.

Mono has generated quite a bit of interest from the Server Core crowd, especially anyone who uses Server Core as their main server. Server Core has a number of advantages that makes it popular with small- to medium-sized companies. It uses far less memory and other resources, runs faster, runs more reliably, and has a far smaller attack surface for those nefarious individuals who want to ruin your day by attacking your server. You can find a complete article about running applications on Server Core using Mono at Mixing-Server-Core-with-NET-Applications/.

Obtaining and Installing Mono

It’s time to obtain and install your copy of Mono. Of course, the first step is to download the product. You can find the various versions of Mono at download.html. This section assumes you’re installing Mono version 2.6.1 on a Windows system. If you need to install Mono on another system, follow the instructions that the Mono Web site provides for those versions. After you complete the download, follow these steps to perform the installation.

  1. Double-click the mono-2.6.1-gtksharp-2.12.9-win32-1.exe file you downloaded from the Mono Web site. You see a Welcome page.
  2. Click Next. You see a License page.
  3. Read the licensing information. Select I Accept the Agreement, and then click Next. You see the Information page shown in Figure 19-1. Unlike most Information pages, this one actually contains a lot of useful information. Make sure you review the information it contains and click on the links it provides as needed. Especially important for keeping updated on Mono is joining the mailing list ( or forums ( You can find these links at the bottom of the Information page.

    Make sure you review this Information page because it contains useful information.
    Figure 19-1: Make sure you review this Information page because it contains useful information.
  4. Read the release information and then click Next. You see the Select Destination Location page shown in Figure 19-2. Normally, you can accept the default installation location. Some developers prefer a less complex path to Mono, such as simply C:Mono, to make it easier to access from the command line. The chapter uses the default installation location.

    Select an installation location for Mono.
    Figure 19-2: Select an installation location for Mono.
  5. Provide an installation location for Mono and then click Next. You see the Select Components page shown in Figure 19-3. The components you select depend on what you plan to do with Mono — you can always change your setup later if necessary. If your only goal is to try Mono for your existing .NET applications and to create some simple IronPython applications, you really don’t need the Gtk# and XSP support. This chapter assumes that you perform a Compact Installation to obtain a minimum amount of support for working with the IronPython sample application.

    Choose the Mono components that you want to install.
    Figure 19-3: Choose the Mono components that you want to install.
  6. Select the components you want to install and then click Next. You see the Select Start Menu Folder page. This is where you choose a name for the folder that holds the Mono components. The default name normally works fine.
  7. Type a name for the Start menu folder (or simply accept the default) and then click Next. You see the Ready to Install page. This page provides a summary of the options that you’ve selected.
  8. Review the installation options and then click Install. You see the Installing page while the installer installs Mono on your machine. After a few minutes, you see a completion dialog box.
  9. Click Finish. You’re ready to begin using Mono.

Creating an IronPython Application with Mono

It’s time to begin working with Mono and IronPython to create an application. Of course, you’ll want to know a bit more about how Mono works before you just plunge into the project, so the first step is to look at Mono from a command line perspective. The first section that follows shows how to create an IPY environment variable and use it to open the IronPython console using Mono whenever you need it. The sections that follow show how to create a project, build a simple IronPython application, and then test the application in a number of ways.

Working at the Command Line

Mono works differently than the .NET Framework. When you want to use the .NET Framework to execute an application, you simply double-click the application and it starts. The same doesn’t hold true for Mono. If you want to execute an application using Mono, you must open the Mono command prompt and start it by specifically specifying Mono. Unfortunately, this limitation has an unusual effect on working with IronPython because you can no longer access IPY.EXE using the Path environment variable. Instead, you must create a special IPY environment variable using the following steps.

  1. Double-click the System applet in the Control Panel and choose the Advanced tab. You see the System Properties dialog box.
  2. Click Environment Variables. You see the Environment Variables dialog box.
  3. Click New in the System Variables section of the Environment Variables dialog box if you want to use IronPython from any account on the machine or the User Variables section if you want to use IronPython only from your personal account. You see a New System Variable or New User Variable dialog box. Except for the title, both dialog boxes are the same.
  4. Type IPY in the Variable Name field.
  5. Type C:Program FilesIronPython 2.6 or the location of your IronPython installation in the Variable Value field.
  6. Click OK three times to add the new environment variable, close the Environment Variables dialog box, and close the System Properties dialog box. You’re ready to begin working with IronPython.

At this point, you’re ready to begin working with Mono. Choose Start ➪ Programs ➪ Mono 2.6.1 for Windows ➪ Mono-2.6.1 Command Prompt to display a Mono command prompt. When you see the Mono command prompt, type Mono “%IPY%IPY.EXE” and press Enter. You’ll see the usual IronPython console.

The first thing you should notice is that the .NET Framework version reporting by the IronPython console is slightly different from the one you normally see. There isn’t any problem with this difference. In fact, it’s the only difference you’re going to notice as you work with the IronPython console. Let’s give it a try so you can see for yourself. Type the following code and you’ll see the standard responses shown in Figure 19-4.

import sys
for ThisPath in sys.path:
print ThisPath

Running IronPython under Mono doesn’t really look any different.
Figure 19-4: Running IronPython under Mono doesn’t really look any different.

If you compare the results you see when running IronPython under the .NET Framework with the results you see when running IronPython under Mono, you won’t notice any differences. In fact, you can try out the applications in this book, and you won’t see any differences at all unless you need to work with an extension or other outside code source (and you might not even see any differences then). Working with Mono simply means you have access to more platforms when working with IronPython, not that you have more limitations.

Defining the Project

The project you create for working with Mono is going to be just a little different from the one you create when working strictly with the .NET Framework. You’ll still start up IronPython using the Visual Studio IDE, but there’s an extra step now: you must start Mono first.

  1. Choose File ➪ Open ➪ Project/Solution. You see the Open Project dialog box shown in Figure 19-5.
    Use Mono as the starting point for your project.
    Figure 19-5: Use Mono as the starting point for your project.


  2. Highlight Mono.EXE in the Program FilesMono-2.6.1bin folder of your machine (unless you used a different installation folder) and click Open. Visual Studio creates a solution based on Mono.
  3. Right-click the Mono entry in Solution Explorer and choose Properties from the context menu. You see the General tab of the Properties window shown in Figure 19-6.

    Set the Mono configuration for your project.
    Figure 19-6: Set the Mono configuration for your project.
  4. Type “C:Program FilesIronPython 2.6IPY.EXE“ -D in the Arguments field (change the folder location to match your IronPython installation).
  5. Click the ellipses in the Working Directory field to display the Browse for Folder dialog box. Locate the folder that contains the project you’re working on and click OK. The project folder appears in the Working Directory field of the Properties window.
  6. Choose File ➪ Save All. You see a Save File As dialog box.
  7. Type the solution name in the Object Name dialog box and click Save.
  8. Right-click the solution entry in Solution Explorer and choose Add ➪ New Item. You see the Add New Item dialog box.
  9. Highlight the Text File template. Type in the Name field and click Add. Visual Studio adds the Python file to your project and automatically opens it for you.

Creating the Code

It’s time to add some code to the IronPython file. This example provides a listing of the modules that IronPython is using. If you compare this list to the one that IronPython provides when you run the application using the .NET Framework, you’ll see the modules in a different order, but otherwise the output is the same. Listing 19-1 shows the code used for this example.

Listin g 19-1: Creating a simple Mono test program

# Obtain access to the sys module.
import sys
# Output a list of modules.
print ‘IronPython Module Listingn’
for ThisMod in sys.modules:
print ThisMod, sys.modules[ThisMod]
# Pause after the debug session.
raw_input(‘nPress any key to continue…’)

This example demonstrates a simple for loop to iterate through the list of modules found in the sys .modules dictionary. In this case, the code prints out two items. First, it prints out the module name. Second, it prints out the module information, which normally includes the module location. As always, the code ends with a pause, raw_input(), so that you can see the output before the window closes.

Running the Application from the IDE

Running the application is the first place you see some potential problems with using Mono. If you click Start Debugging, you see the No Debugging Information dialog box shown in Figure 19-7. If you click Yes, the program will run, but you won’t get any debugging support. This is one of the problems with using Mono exclusively. You’ll probably want to use the normal .NET Framework setup to debug your application first, and then move on to the Mono configuration described in this chapter to test the application under Mono.

Mono doesn’t provide any debugging support that Visual Studio understands.
Figure 19-7: Mono doesn’t provide any debugging support that Visual Studio understands.

To start the application successfully, choose Debug ➪ Start Without Debugging or press Ctrl+F5. The program will run normally and you’ll see the usual message at the end. Pressing Enter displays a second pause as shown in Figure 19-8. It seems that Mono provides its own pause so that you can see the results of executing the program, which is a nice touch for those times when you forget to add a pause of your own.

IronPython displays the list of modules found in the current setup.
Figure 19-8: IronPython displays the list of modules found in the current setup.

Running the Application from the Command Line

Interestingly enough, Mono does come with direct support for IronPython, but Mono supports IronPython 1.1, and the IronPython console supplied with Mono seems to do odd things. Open a Mono command prompt, type IPY, and press Enter. Now try typing 1+1 and pressing Enter. You’ll probably see results like those in Figure 19-9.

The IronPython console provided with Mono leaves a lot to be desired.
Figure 19-9: The IronPython console provided with Mono leaves a lot to be desired.

Of course, the question isn’t about the IronPython console, but whether it can run the example application. Press Ctrl+C to break out of the mess you’re seeing onscreen. Type Y and press Enter when you’re asked whether you want to stop the batch file. Then type IPY and press Enter. You’ll see that the application does indeed work, as shown in Figure 19-10. The number of modules is far smaller than the list shown in Figure 19-8, but it’s correct for the version of IronPython provided with Mono.

You can run the test application using the Mono version of IronPython.
Figure 19-10: You can run the test application using the Mono version of IronPython.

The picture isn’t completely gloomy. Developers are constantly trying new solutions for working with IronPython. You can find a potential fix for the problems described in this section of the chapter at .html. The solution comes with the caveat that it might not work for you.

Interacting with Other .NET Languages under Mono

Mono originally focused its attention on C# development, but later added support for Visual Basic .NET as well. At this point, you can run any Visual Studio 2008–created application written under C# or Visual Basic.NET using Mono within the limitations described in the section “Understanding Mono Limitations” earlier in this chapter. Even DLR code appears to run fine in Mono within the current limits of the product, which aren’t many.


Debugging IronPython Applications

Understanding IronPython Warnings

Warnings are simply indicators that something could be wrong with your application or might not work under all conditions. For example, if you use a deprecated (outdated) function, you might later find that the application refuses to work on all machines. You can use warnings for all kinds of purposes, including providing debugging messages for your application.

The main difference between a warning and an exception is that a warning won’t stop the application. When the interpreter encounters a warning, it outputs the warning information to the standard error device unless the interpreter is ignoring the warning. In some cases, you need to tell the interpreter to ignore a warning because the warning is due to a bug in someone else’s code, a known issue that you can’t fix, or simply something that is obscuring other potential errors in your code. A standard warning looks like this:

__main__:1: UserWarning: deprecated

The elements are separated by colons (:) and each warning message contains the following elements (unless you change the message formatting to meet a specific need).

  • Function name (such as __main__)
  • Line number where the warning appears
  • Warning category
  • Message

You’ll discover more about these elements as the chapter progresses. In the meantime, it’s also important to know that you can issue warnings, filter them, change the message formatting, and perform other tasks using the warning-related functions shown in Table 12-1. You see these functions in action in the sections that follow.

Warning-Related Functions and Their Purpose
Table 12-1: Warning-Related Functions and Their Purpose
Warning-Related Functions and Their Purpose
Table 12-1: Warning-Related Functions and Their Purpose (Continue)

Working with Actions

Before you do too much with warnings, it’s important to know that warnings have an action associated with them. For example, you can choose to turn a particular warning into an exception or to ignore it completely. You can apply actions to warnings in a number of ways using either the filterwarnings() or simplefilter() function. Table 12-2 shows the list of standard warning actions.

Standard Warning Actions
Table 12-2: Standard Warning Actions
Table 12-2 (continued)
Table 12-2 (continued)

It’s important to work with a few warnings to see how filtering works because filters are exceptionally important. In order to use warnings, you import the warnings module. Figure 12-1 shows a typical instance of the default action. Notice that the first time the code issues the warnings .warn(“deprecated“, DeprecationWarning) warning, the interpreter displays a message. (Don’t worry too much about the specific arguments for the warnings.warn()function for right now; you see them explained in the “Working with Messages” and “Working with Categories” sections of the chapter.) However, the interpreter ignores the same warning the second time. If you change the message, however, the interpreter displays another message.

The default action displays each message just one time.
Figure 12-1: The default action displays each message just one time.

Of course, you could always associate a different action with the warnings .warn(“deprecated“, DeprecationWarning) warning. To make this change, you can use the simplefilter() function as shown in Figure 12-2. Now when you issue the warning, it appears every time.

You can set the warning to appear every time.
Figure 12-2: You can set the warning to appear every time.

Unfortunately, as shown in the figure, the change affects every message. Using the simplefilter() function affects every message in every module for a particular message category. Both the newmessage and deprecated messages always appear. Let’s say you want to make just the deprecated message always appear. To perform this task, you use the filterwarnings() function as shown in Figure 12-3 (after first resetting the category using the resetwarnings() function).

Use the filterwarnings() function when you need better control over filtering.
Figure 12-3: Use the filterwarnings() function when you need better control over filtering.

In this case, the warnings.warn(“deprecated“, DeprecationWarning) warning appears every time because its action is set to always. However, the warnings .warn(“newmessage“, DeprecationWarning) warning appears only once because it uses the default action.

You can also set an action at the command line using the –W command line switch. For example, to set the interpreter to always display warning messages, you’d use the –W always command line switch. The –W command line switch accepts an action, message, category, module, or line number (lineno) as input. You can include as many –W command line switches as needed on the command line to filter the warning messages.

The resetwarnings() function affects every warning category and every message in every module. You might not want to reset an entire filtering configuration by using the resetwarnings() function. In this case, simply use the filterwarnings() or simplefilter() function to set the warning back to the default action.

At this point, you might wonder how to obtain a list of the filters you’ve defined. For that matter, you don’t even know if there are default filters that the interpreter defines for you. Fortunately, the warnings class provides two attributes, default_action and filters, which provide this information to you. Listing 12-1 shows how to use these two attributes.

Listin g 12-1: Discovering the default action and installed filters

# Import the required modules.
import warnings
# Display the default action.
print ‘Default action:’, warnings.default_action
# Display the default filters.
print ‘nDefault Filters:’
for filter in warnings.filters:
print ‘Action:’, filter[0],
print ‘Msg:’, filter[1],
print ‘Cat:’, str(filter[2]).split(“‘“)[1].split(‘.’)[1],
print ‘Module:’, filter[3],
print ‘Line:’, filter[4]
# Add new filters.
warnings.filterwarnings(‘always’, message=’Test’, category=UserWarning)
warnings.filterwarnings(‘always’, message=’Test2’, category=UserWarning,
warnings.filterwarnings(‘always’, message=’Test3’, category=UserWarning,
module=’Test’, append=True)
# Display the updated filters.
print ‘nUpdated Filters:’
for filter in warnings.filters:
print ‘Action:’, filter[0],
print ‘Msg:’, filter[1].pattern,
except AttributeError:
print ‘None’,
print ‘Cat:’, str(filter[2]).split(“‘“)[1].split(‘.’)[1],
if len(filter[3].pattern) == 0:
print ‘Module: Undefined’,
print ‘Module:’, filter[3].pattern,
except AttributeError:
print ‘Module: None’,
print ‘Line:’, filter[4]
# Pause after the debug session.
raw_input(‘nPress any key to continue…’)

The code begins by importing the warnings module. It then displays (using warnings.default_ action) the default action that the interpreter will take when it encounters a warning. As shown in Figure 12-4 and described in Table 12-2, the default action is ‘default‘.

The example shows the default actions and filters, along with the output of filter changes.
Figure 12-4: The example shows the default actions and filters, along with the output of filter changes.

The next step is to show the default filters that the interpreter provides for you. It may surprise you to know that the interpreter does include some default filters for the PendingDeprecationWarning, ImportWarning, and BytesWarning, as shown in Figure 12-4. These default filters make the interpreter easier and more enjoyable to use, but could also hide important bugs, so you need to be aware of them.

In order to show how actions and filters work, the example adds three filters using the warnings .filterwarnings() function. The first filter simply tells the interpreter to always display warnings about the Test message provided in the UserWarning category. The second filter specifies that the Test2 warning will appear in the Test module. The third filter specifies that the interpreter should append the warning filter to the end of the filter list, rather than add it to the front of the list as is traditional. You can see the result of all three filter additions in Figure 12-4.

The code used to display the filter information is different in this case because the simple display method used earlier won’t work. What you’ll see as output for the message and module information is something like

<RE_Pattern object at 0x000000000000002C>

which isn’t particularly useful. In order to get information from the message and module elements, you must access the pattern attribute. Unfortunately, this attribute isn’t available with the default filters, so the solution is to create a try…except AttributeError structure, as shown in the code. When the code encounters a default filter entry, it simply prints None as it would have done in the past.

Working with modules presents a special problem. If you look at the first filter declaration, it doesn’t include the Module attribute. Unfortunately, the interpreter takes this omission to mean that you want to create a blank entry, not a null entry. Consequently, the module code also handles the empty entry scenario by saying the module is undefined. If you want to create a null module entry, you must use Module=None as part of your filter declaration.

Notice in Figure 12-4 that the first two filters appear at the front of the list and in reverse order. That’s because the interpreter always adds new filters to the beginning of the list unless you include the append=True attribute. Because the third filter includes this attribute, it appears at the end of the list.

Working with Messages

A message is simply the text that you want to appear as part of the warning. The message is specific information about the warning so that someone viewing the warning will know precisely why the warning is issued. For example, if you issue a DeprecationWarning category warning, the output will automatically tell the viewer that something is deprecated. As a result, your message doesn’t have to tell the viewer that something is deprecated, but it does have to tell the viewer what is deprecated. In many cases, this means supplying the name of the feature such as a method name, attribute, function, or even a class.

Simply telling someone that a feature is deprecated usually isn’t enough information. At a minimum, you must include information about an alternative. For example, you might want to suggest another class or a different function. Even if there is no alternative, you should at least tell the viewer that there isn’t an alternative. Otherwise, the viewer is going to spend hours looking for something that doesn’t exist.

You can’t always tell someone why something is deprecated, but you should when you can. For example, it would be helpful to know that an old function is unstable and that the new function fixes this problem. It’s a good idea to extend this information by saying that the old function is supplied for backward compatibility (assuming that this really is the case).

In some cases, you also need to provide some idea of when a feature is deprecated, especially if the action occurs in the future. Perhaps your organization knows that a function is unstable but hasn’t come up with a fix yet. The fix will appear in the next version of a module as a new function. Having this information will help organizations that rely on your module to plan ahead for required updates.

The point of messages is that they should provide robust information — everything that someone needs to make good decisions. Of course, you don’t want to provide too much information either (anything over three well-written sentences is too much). If you feel the viewer needs additional information, you can always provide it as part of the feature’s help. That way, people who are curious can always find more information. Make sure you note the availability of additional information as part of your message.

Message consistency is another consideration. Remember that filters work with messages as well as categories and other warning elements. If two modules require the same message, make sure you use the same message to ensure filtering works as anticipated. In fact, copying and pasting the message is encouraged to reduce the risk of typographical errors.

If you ever want to see how your message will appear to others, you can use the formatwarning() function to perform the task. Try it out now. Open a copy of the IronPython console and try the following code.

import warnings
warnings.formatwarning(‘Bad Input’, UserWarning, ‘’, 5, ‘import warnings’)

You’ll see results similar to those shown in Figure 12-5. Notice that the output contains linefeeds like this: ‘ UserWarning: Bad Inputn import warningsn‘. When you work with the printed version, the warning appears on multiple lines, as shown near the bottom of Figure 12-5.

Use formatwarning() to see how your warning will appear.
Figure 12-5: Use formatwarning() to see how your warning will appear.

Of course, it’s handy to know the arguments for the formatwarning() function. The following list provides a brief description of each argument.

  • Message: The message you want to display to the user.
  • Category: The warning category you want to use.
  • Filename: The name of the file where the warning occurred (not necessarily the current file).
  • Line number: In most cases, this value contains the line at which the warning is detected, which isn’t always the line at which the warning occurs. For example, it’s possible for a warning to appear at the end of a structure, rather than at the appropriate line within the structure.
  • Line of code: An optional entry that shows the line of code at which the warning occurs. If you don’t supply this argument, the formatwarnings() function defaults to a value of None. The IronPython implementation differs from the standard in this regard. According to the standard, the interpreter is supposed to read the file, obtain the correct line of code, and display the specified line when you don’t provide the appropriate text.

Working with Categories

A warning category is a means of identifying a particular kind of warning. The category makes it possible to group like warnings together and reduces the risk that someone will misinterpret the meaning of a message. In short, a category is a way to pigeonhole a particular message so that others know what you intend. Of course, filtering considers the warning category, so you also need to use the correct category to ensure filtering works as expected. Table 12-3 contains a list of the warning message categories, including a general Warning class that you shouldn’t ever use because it’s too general.

Warning Message Categories
Table 12-3: Warning Message Categories
Warning Message Categories
Table 12-3: Warning Message Categories (Continue)
Warning Message Categories
Table 12-3: Warning Message Categories (Continue)

The warning categories are used with almost every warnings module function. For example, you supply a category when setting a filter or creating a new message. There is always an exception. The resetwarnings() function doesn’t require any input, not even a warning category, because it resets the entire warning environment to a default state.

Obtaining Error Information

Errors will happen in your application, even if you use good exception handling. The handlers you create only react to the errors you know about. Applications also encounter unknown errors. In this case, your application has to have a way to obtain error information and display it to the user (or at least record it in a log file).

It’s important to remember that you normally obtain error information in an application using the exception process described. This section of the chapter is more designed for those situations where you need to work with a generic exception or obtain more detailed information than the specific exceptions provide.

As with many things, IronPython provides a number of methods for obtaining error information. In fact, you might be surprised at how many ways you can retrieve information once you really start looking. The following sections discuss the most common methods for obtaining error information.

Using the sys Module

The sys module contains a wealth of useful functions and attributes you use to obtain, track, and manage error information. One of the first things you should know about the sys module is that it contains the sys.stderr attribute, which defines where the interpreter sends error output. Normally, the output goes to the console window, but you can redirect the error output to any object that has a write() method associated with it, such as a file. If you want to later reset the sys.stderr attribute to the console, the sys.__stderr__ attribute always contains the original output location, so using sys.stderr = sys.__stderr__ performs a reset.

Obtaining error information seems like it should be straightforward, but it’s harder than most developers initially think because obtaining error information often affects application execution in unforeseen ways. In addition, ensuring that the caller receives the right information in a multithreaded application is difficult. The caller could also make unfortunate changes to error information objects, such as the traceback object, creating problems with circular references that the garbage collector is unable to handle. Consequently, you find a lot of functions in sys that look like they should do something useful (and this section covers them), but the two functions you need to keep in mind when working with IronPython are.

  • sys.exc_info(): Returns a tuple containing three items:
    • type: The type of the error, such as ZeroDivisionError. You can find a list of all standard exception types in the exceptions module.
    • value: The human readable string that defines the error. For example, a ZeroDivisionError might provide ZeroDivisionError(‘Attempted to divide by zero.‘,) as a value.
    • traceback: An object that describes the stack trace for an exception. Normally, you won’t use this information directly unless you truly need to obtain the stack trace information, which can prove difficult. If you need stack trace information, consider using the traceback module features instead
  • sys.exc_clear(): Clears the existing exceptions from the current thread. After you call this function, sys.exc_info() returns None for all three elements in the tuple.

The sys.exc_info() function isn’t very hard to use, but you can’t really try it out by executing it directly in the IronPython console. You need to place it within a try…except structure instead. The following code shows a quick demonstration you can type directly into the console window.

type, value = sys.exc_info()[:2]
print type
print value

The example uses a simple division by zero to create an exception. As previously noted, you normally need just the first two elements of the tuple, which you can obtain using sys.exc_info()[:2]. When you execute this code, you see the following output.

<type ‘exceptions.ZeroDivisionError’>
Attempted to divide by zero.

Some IronPython sys module functions affect only the interactive thread (which means they’re safe to use in multithreaded applications because there is only one interactive thread in any given session). You could use these functions to determine the current type, value, and traceback for an exception, but only for the interactive session, which means these functions are completely useless for your application. In most cases, you avoid using these three functions.

  • sys.last_traceback()
  • sys.last_type()
  • sys.last_value()

You could run into problems when working with some functions in the sys module. For example, these three functions are global, which means they aren’t specific to the current thread and are therefore, unsafe to use in a multithreaded application.

  • sys.exc_type()
  • sys.exc_value()
  • sys.exc_traceback()

Interestingly enough, these three functions are also listed as deprecated (outdated) in most Python implementations (including IronPython). As with all IronPython modules, you also have access to low-level functions in the sys module. The following list is low-level modules you can use for special needs, but won’t normally use in your application.

  • sys.excepthook(type, value, traceback): The system calls this low-level function each time it generates an exception. To use this function, you supply the same tuple of values as you receive when you call sys.exc_info().
  • sys._getframe([depth]): The system calls this low-level function to display a frame object from the call stack. If the caller supplies a depth value, the frame object is at that call stack depth. The default depth value setting is 0. IronPython doesn’t appear to implement this function, but you may encounter it in other versions of Python, so it pays to know about this function.

If you want to control how much information the interpreter provides when you request a traceback, you can always set the sys.tracebacklimit attribute. The sys.tracebacklimit attribute defaults to 1,000. It doesn’t actually appear when you perform a dir() command. In fact, until you set it, printing the sys.tracebacklimit attribute returns an AttributeError. Use code like this

sys.tracebacklimit = 3

to modify the traceback level. Now when you try to print the sys.tracebacklimit attribute, you get back the value you supplied.

Using the traceback Module

The traceback module adds to the capabilities of the sys module described in the “Using the sys Module” section of the chapter. In addition, it adds to the standard exception handling capabilities of IronPython by making it easier to obtain complex information about exceptions in general. The traceback module does focus on tracebacks, which are the IronPython equivalent of a call stack.

The most common call is traceback.print_exc(). Essentially, this call prints out the current exception information. You can use it in a try…except structure, much as you’d use the sys.exc_info() function, but with fewer limitations. Figure 12-6 shows a typical view of the traceback.print_exc() function in action.

Obtain traceback information with ease using the traceback.print_exc() function.
Figure 12-6: Obtain traceback information with ease using the traceback.print_exc() function.

You may find that you want a string that you can manipulate, rather than direct output. In this case, you use the traceback.format_exc() function and place its output in a variable. The information is the same as shown in Figure 12-6, but you have the full capability of string manipulation functions to output the information in any form desired.

All of the traceback output functions include a level argument that defines how many levels of trace information you want. The default setting provides 1,000 levels, which may be a little more information than you want. Many of the traceback output functions also include a file argument that accepts the name of a file you can use for output (such as application logging). If you don’t provide the file argument, it defaults to using the sys.stderr device (normally the console).

Some of the traceback functions are macros for longer function combinations. For example, when you type traceback.print_last(), what you’re really doing is executing print_exception(sys.last_ type, sys.last_value, sys.last_traceback, limit, file). Obviously, typing traceback .print_last() is a lot less work!

IronPython is missing some extremely important functionality when it comes to the traceback module. You can’t use traceback.print_stack(), traceback.extract_stack(), or traceback.format_ stack() to obtain current stack information. The code shown in Figure 12-7 is standard output when working with Python. Figure 12-8 shows what happens when you execute this code in IronPython. Instead of getting a nice stack trace you can use for debugging (see Figure 12-7), you get nothing at all (see Figure 12-8). This is a known issue (see the issue information at http://ironpython.codeplex .com/WorkItem/View.aspx?WorkItemId=25543).

Python provides full stack information you can use for debugging.
Figure 12-7: Python provides full stack information you can use for debugging.
IronPython lacks support for stack traces, making debugging significantly more difficult.
Figure 12-8: IronPython lacks support for stack traces, making debugging significantly more difficult.

The traceback module contains a number of interesting functions that you can use to debug your application. You can see these functions described at .html. Don’t assume that all of these functions work as they do in Python. There are currently a number of outstanding traceback module issues for IronPython.

Debugging with the Python Debugger

You might not know it, but Python and IronPython come with a debugger module, pdb (for Python debugger). Like any module, you have full access to the debugger source code and can modify it as needed. This section describes the default debugger performance.

It’s possible to use pdb with any Python file by invoking the debugger at the command line using the –m command line switch. Here’s how you’d invoke it for the example shown in Listing 12-1.

IPY -m pdb

Unfortunately, using this command line format limits what you can do with the debugger. Although you can single step through code, you can’t work with variables easily and some other debugger commands may not work as anticipated.

The debugger works better if you configure your application to use a main() module. Most of the examples in this book don’t use a main() function for the sake of simplicity, but you should use one for any production code you create. The file contains the modifications to provide a main() function. Essentially, you encase the code in Listing 12-1 in the main() function and then call it using the following code:

# Create an entry point for debugging.
if __name__ == “__main__“:

Using the debugger is very much like old-style DOS debuggers such as the Debug utility. You issue commands and the debugger responds without output based on the application environment and variable content. The lack of a visual display may prove troublesome to developers who have never used a character-mode debugger, but pdb is actually more effective than any of the graphical alternatives in helping you locate problems with your application — at least, in the Python code. Use these steps to start the pdb:

  1. Start the IronPython console by selecting it from the Start menu or typing IPY at the command line.
  2. Type import pdb and press Enter to import the Python debugger.
  3. Type import ApplicationName where ApplicationName is the name of the file that contains your application and press Enter. For example, if your application appears in, then you’d type import ShowFilters2 (without the file extension) and press Enter.
  4. Type‘ApplicationName.FunctionName()‘) where ApplicationName is the name of the application and FunctionName is the name of the function you want to test, and press Enter. For example, if your application is named ShowFilters2 and the function you want to test is main(), you’d type‘ShowFilters2.main()‘) and press Enter. The standard console prompt changes to a pdb prompt, as shown in Figure 12-9.
The Python debugger uses a special pdb prompt where you can enter debugging commands.
Figure 12-9: The Python debugger uses a special pdb prompt where you can enter debugging commands.

Now that you have a debugger prompt, you can begin debugging your application. Here is a list of standard debugger commands you can issue:

  • a or args: Displays the list of arguments supplied to the current function. If there aren’t any arguments, the call simply returns without displaying anything.
  • alias: Creates an alias for a complex command. For example, you might need to use a for loop to drill down into a list to see its contents. You could use an alias to create a command to perform that task without having to write the complete code every time. An alias can include replaceable variables, just as you would use for a batch file.
  • b or break: Defines a breakpoint when you supply a line number or a function name. When you provide a function name, the breakpoint appears at the first executable line within the function. If an application spans multiple files, you can specify a filename, followed by a colon, followed by a line number (no function name allowed), such as ShowFilters2:1. A breakpoint can also include a condition. To add the condition, follow the breakpoint specification with a comma and the condition you want to use, such as ShowFilters2:2, Filter == None. If you type just b or break, the debugger shows the current breakpoints. Use the cl or clear command to clear breakpoints you create.
  • bt, w, or where: Prints a stack trace with the most current frame at the bottom of the list. You can use this feature to see how the application arrived at the current point of execution.
  • c, cont, or continue: Continues application execution until the application ends or the debugger encounters a breakpoint.
  • cl or clear: Clears one or more breakpoints. You can specify the breakpoint to clear by providing one or more breakpoint numbers separated by spaces. As an alternative, you can supply a line number or a filename and line number combination (where the filename and line number are separated by a colon).
  • commands: Defines one or more commands that execute when the debugger arrives at a line of code specified by a breakpoint. You include the optional breakpoint as part of the commands command. If you don’t supply a breakpoint, then the commands command refers to the last breakpoint you set. To stop adding commands to a breakpoint, simply type end. If you want to remove the commands for a breakpoint, type commands, press Enter, type end, and press Enter again. A command can consist of any interactive Python or debugger command. For example, if you want to automatically move to the next line of code, you’d simply add step as one of the commands.
  • condition: Adds a condition to a breakpoint. You must supply a breakpoint number and a Boolean statement (in string format) as arguments. The debugger doesn’t honor a breakpoint with a condition unless the condition evaluates to True. The condition command lets you add a condition to a breakpoint after defining the breakpoint, rather than as part of defining the breakpoint. If you use condition with a breakpoint, but no condition, then the debugger removes a condition from a breakpoint, rather than adding one.
  • d or down: Moves the frame pointer down one level in the stack trace to a new frame.
  • debug: Enters a recursive debugger that helps you debug complex statements.
  • disable: Disables one or more breakpoints so that they still exist, but the debugger ignores them. You can separate multiple breakpoint numbers with spaces to disable a group of breakpoints at once.
  • enable: Enables one or more breakpoints so that the debugger responds to them. You can separate multiple breakpoint numbers with spaces to enable a group of breakpoints at once. Enabling a breakpoint doesn’t override any conditions that are set on the breakpoint. The condition must still evaluate to True before the debugger reacts to the breakpoint.
  • EOF: Tells the debugger to handle the End of File (EOF) as a command. Normally, this means ending the debugger session once the debugger reaches EOF.
  • exit or q or quit: Ends the debugging session. Make sure you type exit, and not exit(), which still ends the IronPython console session.
  • h or help: Displays information about the debugger. If you don’t provide an argument, help displays a list of available debugging commands. Adding an argument shows information about the specific debugging command.
  • ignore: Creates a condition where the debugger ignores a breakpoint a specific number of times. For example, you might want to debug a loop with a breakpoint set at a specific line of code within the breakpoint. You could use the ignore command to ignore the first five times through the loop and stop at the sixth. You must supply a breakpoint number and a count to use this command. The debugger automatically ignores the breakpoint until the count is 0.
  • j or jump: Forces the debugger to jump to the line of code specified as an argument.
  • l or list: Displays the specified lines of code. If you don’t supply any arguments with the command, the debugger displays 11 lines of code starting with the current line. When you supply just a starting point (a code line number), the debugger displays 11 lines of code starting with the starting point you specify. To control the listing completely, supply both a starting and ending point.
  • n or next: Continues execution to the next line of code. If the current line of code is a function, the debugger executes all of the code within the function and stops at the next line of code in the current function. In sum, this command works much like a step over command in most other debuggers.
  • p: Prints the value of an expression as the debugger sees it. Don’t confuse this command with the IronPython print() function, which prints an expression based on how IronPython sees it.
  • pp: Performs a pretty print. Essentially, this command is the same as the p command, except that the debugger interprets any control characters within the output so that the output appears with line feeds, carriage returns, tabs, and other formatting in place.
  • r or return: Continues execution until the current function returns. This command works much like a step out command in most other debuggers
  • restart: Restarts the current application at the beginning so that you can retest it. The command lets you supply optional arguments that appear as part of the sys.argv attribute. This command preserves debugger history, breakpoints, actions, and options.
  • run: Starts the application when used within Python as demonstrated earlier in this section. However, this command is simply an alias for restart when used within the debugger environment.
  • s or step: Executes the current line of code and then moves to the next line of code, even if that line of code appears within another function. This command works much like a step into command in most other debuggers
  • tbreak: Performs precisely like a break command, except that the debugger removes the breakpoint when the debugger stops at it the first time. This is a useful command when you want to execute a breakpoint just one time.
  • u or up: Moves the frame pointer up one level in the stack trace to an old frame.
  • unalias: Removes the specified alias (see the alias command for additional details).
  • unt or until: Continues execution until such time as the line number is greater than the current line number or the current frame returns. This command works much like a combination of the step over and step out commands in most other debuggers (see next, return, and step for other stepping commands).
  • whatis: Displays the type of the argument that you supply.

Debugging with the CLR Debugger

The CLR debugger, CLRDbg.EXE, is part of the .NET Framework SDK. You find it in the GuiDebug folder of your .NET Framework installation or in the Program FilesMicrosoft.NETSDKv2.0 GuiDebug folder. However, if you installed Visual Studio without installing the SDK, you might not see a GuiDebug folder. In this case, you can download and install the .NET Framework SDK separately. You can obtain the .NET Framework SDK for various platforms at these locations.

  • .NET Framework 2.0:
  • .NET Framework 3.0:
  • .NET Framework 3.5:
  • .NET Framework 3.5 SP1: aa569263.aspx

This section relies on the CLRDbg.EXE version found in the .NET Framework 2.0 SDK. However, the instructions work fine for every other version of the CLR debugger as well. The newer versions of the debugger may include a few additional features that you won’t likely use or need when working with IronPython. The following steps describe how to start the debugger.

  1. Start the CLR debugger. If you installed the .NET Framework SDK separately, choose Start ➪ Programs ➪ Microsoft .NET Framework SDK v2.0 ➪ Tools ➪ Microsoft CLR Debugger. It’s also possible to start the CLR debugger from the command line by typing CLRDbg and pressing Enter as long as the debugger’s location appears in the path. You see the Microsoft CLR Debugger window.

    Provide the information needed to debug your application.
    Figure 12-10: Provide the information needed to debug your application.
  2. Choose Debug ➪ Program to Debug. You see the Program to Debug dialog box shown in Figure 12-10. This dialog box is where you enter the IronPython executable and script information, along with any command line switches you want to use.
  3. Click the ellipsis (…) in the Program field and use the Find Program to Debug dialog box to locate the IPY.EXE file. Click Open to add the IPY.EXE information to the dialog box.
  4. Type –D in the Arguments field (the example uses –D ShowFilters2 .py). Type any additional command line arguments you want to use while working with the application.
  5. Click the ellipses in the Working Directory field and use the Browse for Working Directory dialog box to locate the script directory (not the IPY.EXE directory). Click Open to select the working directory.
  6. Click OK. The CLR debugger prepares the debugging environment. However, you don’t see any files opened. You must open any files you wish to interact with as a separate step.
  7. Choose File ➪ Open ➪ File. Locate the source files you want to debug ( for the example). Click Open. You see the source file opened in the Microsoft CLR Debugger window. Figure 12-11 shows an example of how your display should look when working with the example. (The figure shows the debugger in debugging mode.)

    Open the source files you want to debug.
    Figure 12-11: Open the source files you want to debug.

At this point, you can begin working with the script just as you would with the Visual Studio debugger. The next section, “Using Visual Studio for IronPython Debugging,” discusses this debugger in more detail.

Using Visual Studio for IronPython Debugging

When you click Start Debugging, the debugger stops at the line of code as you might expect. Now, create a watch for both filter and filters. As shown in Figure 12-12, you can drill down into a complex object and examine it. In many cases, you must look through the Non-Public Members to find what you want, but the data is there for you to peruse. In this case, you can see all five elements in filters and even see the pattern data. Notice that the Type column is truly helpful in showing you which types to use when interacting with the data.

Watches let you drill down into both Python and .NET data.
Figure 12-12: Watches let you drill down into both Python and .NET data.

Unfortunately, Figure 12-12 also shows the other side of the coin. You can’t access warnings .filters even though it should be available. The Visual Studio debugger often produces poor results when working with Python-specific objects. If you have a need for working with these objects.

As shown in Figure 12-13, you can use the Immediate window to query objects directly. However, you can’t drill down into an object as you might have in the past. Consequently, entering ? filter works just fine, but entering ? filter[0] doesn’t.

The Immediate window is only partially useful when working with IronPython.
Figure 12-13: The Immediate window is only partially useful when working with IronPython.

In general, you’ll find that using the Python debugger works better for some Python-specific applications. Even though the Visual Studio debugger does provide a nice visual display, the quality of information isn’t quite as good. Of course, the picture changes when your application mixes Python and .NET code. In this case, the Visual Studio debugger can be your best friend because it knows how to work with the .NET objects.

 Defining and Using Exceptions

Exceptions are an essential part of any application. In fact, most developers have no problem using them at all. Unfortunately, many developers also misuse exceptions. Instead of providing robust code that handles common problems, the developer simply raises an exception and hopes someone else does something about the issue. Exceptions are generally used to address conditions that you couldn’t anticipate.

IronPython provides access to both Python exception and .NET exceptions, so the developer actually has twice as many opportunities to catch errors before they become a problem. It’s important to use the correct kind of exception handling. If you’re working with .NET code, you’ll normally use a .NET exception. Python exceptions address anything that isn’t .NET-specific. The following sections provide additional information about exceptions.

Implementing Python Exceptions

Python provides a number of standard exceptions, just as the .NET Framework does. You find these exceptions in the exceptions module. To see the list of standard exceptions, import the exceptions module and perform a dir() command on it, as shown in Figure 12-14.

Python stores its list of standard exceptions in the exceptions module.
Figure 12-14: Python stores its list of standard exceptions in the exceptions module.

The various exceptions provide different amounts of information. For example, when working with an IOError, you can access the errno, filename, message, and strerror attributes. On the other hand, a ZeroDivisionError provides only the message attribute. You can use the dir(exceptions .ExceptionName) command to obtain information about each of the exception attributes.

As with .NET, you can create custom exceptions using Python. The documentation for creating a custom exception is a bit sketchy, but you can create a custom exception (usually with the word Error in the name by convention) for every need. Listing 12-2 shows all of the Python exception basics, including creating a relatively flexible custom exception.

Listin g 12-2: Discovering the default action and installed filters

# Import the required modules.
import exceptions
# Define a custom exception.
class MyError(exceptions.Exception):
errno = 0
message = ‘Nothing’
def __init__(self, errno=0, message=’Nothing’):
self.errno = errno
self.message = message
def __str__(self):
return repr(self.message)
# Display the Error exception list.
for Error in dir(exceptions):
if ‘Error’ in Error:
print Error
# Create a standard exception.
except ZeroDivisionError as (errinfo):
print “nDivide by Zero error: {0}“.format(errinfo)
# Create a custom exception.
raise MyError(5, ‘Hello from MyError’)
except MyError, Info:
print “Custom Error({0}): {1}“.format(Info.errno, Info.message)
# Pause after the debug session.
raw_input(‘nPress any key to continue…’)

The code begins by importing exceptions. The for loop lists all of the exceptions (the names of the types) found in exceptions, as shown in Figure 12-15. Notice how the code uses if ‘Error‘ in Error to locate just the exceptions in the module. This technique is useful for a lot of tasks in IronPython where you need to filter the output in some way.

The example shows basic exception handling and creation for Python.
Figure 12-15: The example shows basic exception handling and creation for Python.

The next bit of code raises a standard exception and then handles it. The output shows just a message. Notice that this exception relies on the as clause to access the error information.

It’s time to look at a custom exception, which begins with the MyError class definition. At a minimum, you should define both __init__() and __str__() or the exception won’t work as intended. Notice how __init__() assigns default values to both errno and message. You can’t depend on the caller to provide this information, so including default values is the best way to approach the problem. You can always assign other values later in the code based on the actual errors.

Make sure you create attributes for any amplifying information you want the caller to have. In this case, the example defines two attributes errno and message.

The __str__() method should return a human-readable message. You can return just the text portion of the exception or return some combination of exception attributes. The important thing is to return something that the developer will find useful should the exception occur. You can test this behavior out with the example by typing raise MyError. Here’s the output you’ll see.

Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
__main__.MyError: ‘Nothing’

Because you didn’t provide any arguments, the output shows the default values. Try various combinations to see how the output works. The example tries the exception in a try…except statement. Notice that a custom exception differs from a standard exception in that you don’t use the as clause and simply provide a comma with a variable (Info in this case) instead. You can then use the variable to access the exception attributes as shown. Figure 12-15 shows how the custom exception outputs information. Of course, your custom exception can provide any combination of values.

Implementing .NET Exceptions

In general, you want to avoid using .NET exceptions in your IronPython applications, except in those cases where you need to provide specific functionality for .NET code. The problem is that IronPython views such exceptions from a Python perspective. Consequently, trapping .NET exceptions can prove tricky unless you spend some time working with them in advance.

Many .NET exceptions are available in the System assembly so you need to import it before you can perform any serious work. After that, you can raise a .NET exception much as you do a Python exception. Handling the exception follows the same route as using a try…except statement. However, the problem is that the exception you get isn’t the exception you raised. Look at Figure 12-16 and you see that the ArgumentException becomes a ValueError and the ArithmeticException becomes an ArithmeticError.

Sloppy programming will cost you so much time as to make the programming experience a nightmare. Using a combination of warnings, error trapping, and exceptions will make your code significantly easier to debug. Of course, choosing the right debugging tool is also a requirement if you want to go home this weekend, rather than spending it in your office debugging your latest application.




Understanding the Use of Indentation and Capitalization in IronPython

Most application programming languages have rules that help the compiler or interpreter understand what you mean. For example, when working with C, C++, Java, C#, and a number of other languages, you use opening and closing braces to indicate the code that belongs within a structure such as a function or loop. Without these opening and closing braces, the compiler or interpreter for the target language would never be able to understand what you mean — these braces add structure to your application code. Likewise, IronPython relies on rules, indentation and capitalization, to help the interpreter understand your code.

The interpreter does help you with the indentation. The amount you indent a line doesn’t seem to matter. Using tabs instead of spaces doesn’t seem to matter either, but using tabs will ensure that you don’t run into problems seeing the indentation in code properly. Open a copy of IPY to follow along with the discussion in this section. Try the following steps and you’ll discover how the interpreter helps you discover when to indent.

  1. Type SomeText = ‘Hello‘ and press Enter. You’ll see that the interpreter adds three greater-than signs (>>>). The >>> is a primary prompt and tells you that you don’t need to add any indentation.
  2. Type if SomeText == ‘Hello‘: and press Enter. Now you’ll see that the interpreter adds three dots (…) to the next line. The … is the secondary prompt. It tells you that you’ve entered a structure.
  3. Type print SomeText and press Enter. The interpreter displays an error message like the one shown in Figure 2-12. The interpreter expected an indented block, but you didn’t provide any indentation, so the block failed.
  4. Repeat Step 2 again. Press Tab. Type print SomeText and press Enter. This time, the entry succeeds, as shown in Figure 2-13. Notice that the interpreter has displayed … again so that you can continue the block if desired. In fact, the block continues until you end it by not indenting an entry.
  5. Press Enter. The interpreter displays the word Hello. The interpreter will keep track of a block until you finish entering the last line of code. It then evaluates the block and performs all of the tasks it contains.

Not indenting at a secondary prompt produces an error.

A properly indented entry succeeds.

Now that you have the basic idea about indentation, it’s time to consider capitalization. IronPython is case sensitive. So, if you type:

If SomeText == ‘Hello’:

and press Enter, the code will fail. Figure 2-14 shows that the error information you receive isn’t straightforward. All that the interpreter tells you is that the token it received is unexpected (a token is a single word that the interpreter parses to discover what you want to do). The interpreter will provide more precise information for some errors. Type:

if SomeText == ‘Hello’:
print sometext

and press Enter. This time you get precise error information, as shown in Figure 2-15. The interpreter tells you that the error lies in line 2 of the block and that the error occurred because SomeText isn’t defined.

Some error messages are ambiguous.

The interpreter can provide precise error information for certain classes of error.

The point of this exercise is that the interpreter will catch indentation and capitalization errors. In some cases, you might scratch your head for a while trying to figure out what went wrong, but the interpreter is accurate about locating such problems for you.

It doesn’t matter whether you use tabs or spaces for indentation. Try the example out using spaces instead of a tab. You’ll discover that it works just fine. However, using tabs provides uniform spacing that is easier to see when you’re reading the code. If you’re not careful, you might use one space in one location and four in the next, making it hard to tell when something really is indented.

Using Visual Studio to Create IronPython Applications

You might have looked at the New Project dialog box after you installed IronPython, assuming that you’d find a series of new project templates. Unfortunately, you won’t find any new templates for IronPython. The current version of the product doesn’t include anything you can use directly. Fortunately, you can still create a project for IronPython projects and use Visual Studio to edit and debug it. The following sections take you through a simple configuration scenario and then show the resulting project in action.

Creating the Project

Before you do anything else, you must create a project to hold your IronPython application. The following steps show you how to perform this task.

  1. Open Visual Studio, but don’t open any project or template files.
  2. Choose File ➪ Open ➪ Project/Solution. You’ll see the Open Project dialog box shown in Figure 2-1.

    Use the Open Project dialog box to start the project.

  3. Locate and highlight IPY.EXE (normally found in the Program FilesIronPython 2.6 folder). Click Open. Visual Studio creates a solution based on IPY.EXE, as shown in Figure 2-2. You must still configure this solution.
    IPY.EXE becomes the focal point for a new solution.
  4. Right-click IPY in Solution Explorer and choose Properties from the context menu. You’ll see the General tab of the Properties page shown in Figure 2-3. (Your display may differ slightly from the one shown in Figure 2-3 based on your machine configuration and the Visual Studio 2010 edition you use.) At a minimum, you must change the Arguments and Working Directory fields to match your project.
    Modify the properties to match your project requirements.
  5. Select the Arguments field. Type -D NameOfProject, where NameOfProject is a Python (.py) file. For example, the example project uses, so you’d type -D Remember that the -D command line switch turns on debugging. You can find other command line arguments listed in the “Understanding the IPY.EXE Command Line Syntax” section. Include any other command line switches you want to use in the Arguments field.
  6. Select the Working Directory field. Visual Studio will default to using the Program FilesIronPython 2.6 directory — a directory that you’re unlikely to use to hold your source code files. Change the Working Directory to match your source code directory. Click the ellipses to locate the directory on your hard drive using the Browse for Folder dialog box.
  7. Choose File ➪ Save All. You’ll see the Save File As dialog box shown in Figure 2-4.
    Save the resulting solution before you do anything else.
  8. Locate the folder you want to use to save the project in the Save In field.
  9. Type a name for the solution in the Object Name field. Click Save. Visual Studio will save the project to the folder you selected.

Adding Existing Files to the Project

At this point, you have a project without any files in it. Yes, you could run the project and you’d see what you’d expect, but you can’t debug the IronPython file or edit it. The following steps tell how to add a file to your project.

  1. Right-click the solution entry in Solution Explorer (not the IPY project entry) and choose Add ➪ Exiting Item from the context menu. You’ll see the Add Exiting Item dialog box shown in Figure 2-5.
    Add your existing Python files to the project.
  2. Locate the existing file you want to use and click Open. Visual Studio adds a Solution Items folder to Solution Explorer and places the file you selected in the Solution Items folder, as shown in Figure 2-6. In addition, Visual Studio automatically opens the file for you.
    The Solution Items folder holds the Python files you add.

Adding New Files to the Project

Once you get used to working with Visual Studio, you may decide to create files from scratch using the Visual Studio IDE. In this case, you need to add blank (new) files to the project. The following steps show you how to perform this task.

  1. Right-click the solution entry in Solution Explorer and choose Add ➪ New Item from the context menu. You’ll see the Add New Item dialog box shown in Figure 2-7.
    You can use the Visual Studio IDE to create new Python files.
  2. Highlight the Text File entry. Visual Studio will assume you want to create a text (.TXT) file, but you can change the extension to anything you want.
  3. Type the name of the Python file you want to create in the Name field. Make certain that your file has a .py extension or the IronPython interpreter may not work with it.
  4. Click Add. Visual Studio adds the file to Solution Explorer (similar to the addition shown in Figure 2-6) and automatically opens the file for editing.

IronPython Project Limitations

The project you create using this technique has some serious limitations. Here’s a partial list of the things that you won’t see in your IronPython project that you’ll normally see in other Visual Studio projects.

  • Color support for keywords or other special text
  • IntelliSense
  • New Items dialog support
  • Immediate window (debugging)
  • Command window (when working with variables during debugging)

Debugging the Project

This section assumes you’re using the example found in Chapter 1 and that you’ve created a project for it. Start by placing a breakpoint on the first line of the application (print(‘5 * 10 =‘),); then place a second breakpoint at the beginning of the function (def mult(a, b):). You can do this by placing your cursor on the line and pressing F9 or choosing Debug ➪ Toggle Breakpoint. You should see the breakpoint shown in Figure 2-8.

Visual Studio helps you debug your IronPython applications.

At this point, you can begin debugging your application. The following steps get you started.

  1. Press F5 or click Start Debugging to begin debugging your application. Starting the debug process can take a while because Visual Studio has to start a copy of the IronPython interpreter. Visual Studio stops at the function definition. IronPython makes a list of function definitions when it starts the application.
  2. Click Step Over. You’ll move to the first line of the application. At this point, the debugger begins executing your application code.
  3. Click Step Over again. If you look at the command prompt at this point, you’ll see that it contains the expected output text, but not the answer, as shown in Figure 2-9. Now, if you clicked Step Over again, you’d see the output from the Mult() function, but you wouldn’t actually see the code in Mult() execute. The next step shows how to get inside a function so you can see how it works.
    The console screen will show the results of tasks performed in your application code.
  4. Press F5 or click Start Debugging. The application will stop within Mult(). Being able to stop within a function is the reason for setting the second breakpoint at the beginning of this procedure. Now you can use Step Over to execute the lines of code one at a time. Notice the Debug History window. You can select entries in this window to see what the IronPython interpreter has been doing in the background, as shown in Figure 2-10.
    Use the Debug History window to see what the interpreter is doing in the background.
  5. Press F5 or click Start Debugging. The application will end.

Visual Studio does provide you with access to many standard debugging features. For example, you can place variables in the Watch windows and see their values as shown in Figure 2-11. You also have access to the Call Stack and Output windows. The Immediate and Command windows don’t work as you might expect them to, so you need to inspect variables and perform other variable-related tasks using the Watch windows.

The Watch windows provide access to variable information.

Using the IronPython Console

The IronPython console is the best place to begin working with IronPython. You can enter a few statements, test them out, and then work out additional details without too many consequences. In addition, because the console is interactive, you obtain immediate feedback, so you don’t have to wait for a compile cycle to discover that something you’re doing is completely wrong. In fact, even after you’ve mastered IronPython, you’ll find that you use the console to try things out. Because IronPython is a dynamic language, you can try things without worrying about damaging an application. You can test things quickly using the console and then include them in your application. The following sections describe the IronPython console and how to use it.

Opening and Using the Default Console

The IronPython console is an application provided with the default installation. You access it using the Start ➪ Programs ➪ IronPython 2.6 ➪ IronPython Console command. The console, shown in Figure 1-3, looks something like a command prompt, but it isn’t.

The IronPython console looks something like a command prompt.

Notice that the top of the window tells you which version of IronPython you’re using and which version of the .NET Framework it’s running on. This is important information because it helps you understand the IronPython environment and what limitations you have when working with IronPython. Below this first line, you’ll see some commands that Microsoft thought you might find useful. The “Getting Help with Any Function” section of the chapter tells you more about the Help command.

To use the console, simply type the commands you want to issue. When you’re done, IronPython will execute the commands and output any result you requested. A command need not be a function call or an object instantiation as it is in other languages. For example, type 2 + 2 right now and then press Enter. You’ll see the result of this simple command, as shown in Figure 1-4.

IronPython is dynamic and the console is interactive.

Whenever you want to end a particular task, such as working with Help, press Enter a second time. The console will take you to the previous level of interaction.

Getting Help with Any Function

You can get help with any function in the console. If you simply type help and press Enter in the console, IronPython tells you how to request interactive help or help about a specific object. To begin interactive help, type help() and press Enter. You’ll see the interactive help display shown in Figure 1-5.

Interactive help lets you ask questions about IronPython.

Let’s say you have no idea of what you want to find. Console help provides you with a list of words you can type to get general help. These terms are:

  • Modules
  • Keywords
  • Topics

Type any of these terms and press Enter. You’ll see a list of additional words you can type, as shown in Figure 1-6 for modules. Using this technique, you can drill down into help and locate anything you want. In fact, it’s a good idea to spend some time in help just to see what’s available. Even advanced developers can benefit from this approach — I personally follow this approach when I have time to increase my level of knowledge about all of the languages I use.

You might know about the topic you want to find. For example, you might know that you want to print something to screen, but you don’t quite know how to use print. In this case, type help(‘print‘) and press Enter. Figure 1-7 shows the results. You see complete documentation about the print keyword.

Understanding the IPY.EXE Command Line Syntax

When you open a console window, what you’re actually doing is executing IPY.EXE, which is the IronPython interpreter. You don’t have to open a console window to use IPY.EXE. In fact, you normally won’t. It’s possible to execute IronPython applications directly at the command line. The following sections discuss IPY.EXE in more detail.

Adding IPY.EXE to the Windows Environment

Before you can use IPY.EXE effectively, you need to add it to the Windows path statement. The following steps provide a brief procedure.

  1. Open the Advanced tab of the Computer (or My Computer) applet.
  2. Click Environment Variables. You’ll see an Environment Variables dialog box.
  3. Highlight Path in the System Variables list. Click Edit. You’ll see the Edit Environment Variable dialog box.
  4. Select the end of the string that appears in the Variable Value field. Type ;C:Program FilesIronPython 2.6 and click OK. Make sure you modify this path to match your IronPython configuration.
  5. Click OK three times to close the Edit System Variable, Environment Variables, and System  Properties dialog boxes. When you open a command prompt, you’ll be able to access the IronPython executables.

Drill down into help to find topics of interest.

The console also provides the means to obtain precise help about any module, keyword, or topic.

Executing an Application from the Command Prompt

Normally, you execute an application by typing IPY <Python Filename> and pressing Enter. Give it a try now. Open a command prompt, type CD Program FilesIronPython 2.6Tutorial, and press Enter. You’re in the sample files supplied by IronPython. Type IPY and press Enter. You’ll see a window displayed. When you click your mouse in the window, you see the word Hello displayed at each click point, as shown in Figure 1-8. If you look at the command prompt window at this point, you’ll see that the mouse cursor is blinking but you can’t type anything because the command
prompt is waiting for the IronPython interpreter to end. When you click the Close button, the application ends and you can again type something at the command prompt.

Understanding the IPY.EXE Standard Command Line Switches

Sometimes you need to provide IPY.EXE with more information about a particular application. In this case, you can use one of the command line switches shown in the following list to provide IPY.EXE with the required information. It’s important to note that the command line switches are case sensitive; –v isn’t the same as –V.

The WFDemo shows that you can create windowed environments for IronPython applications.

–3: Forces the interpreter to warn about Python 3 compatibility issues in your application.

–c cmd: Specifies a command you want to execute. This command line switch must appear last on the line because
anything after this command line switch is interpreted as a command you want to execute. For example, if you type ipy -c “print (‘Hello‘)“, the interpreter will output the word Hello.

–D: Enables application debugging.

–E: Ignores any environment variables that you specified as part of the Windows environment variable setup or on the command line after you started it. Some applications may not run after you use this command line switch because they won’t be able to find modules and other files they need.

–h: Displays a complete list of the command line arguments.

–i: Displays the console after running the script. You can then inspect the results of the script using console commands.

–m module: Runs library module as a script.

–O: Tells the interpreter to generate optimized code, which means you can’t perform debugging, but the application will run faster.

–OO: Removes all of the doc strings and applies –O optimizations so that the application runs even faster than using the –O command line switch alone.

–Q arg: Specifies use of one of several division options. You can use any of these values.

  • –Qold (default): The precision of the output depends on the operators used. For example, if you divide two integers, you get an integer as output.
  • –Qwarn: Outputs warnings about a loss of precision when performing division using integers.
  • –Qwarnall: Outputs warnings about all uses of the classic division operator.
  • –Qnew: The output is always a precise floating point fraction.

–s: Specifies that the interpreter shouldn’t add the user site directory to sys.path.

–S: Specifies that the interpreter shouldn’t imply that it should execute the import site command on initialization.

–t: Outputs warnings about inconsistent tab usage, which can lead to code interpretation problems.

–tt: Outputs errors for inconsistent tab usage. Inconsistent tab usage can lead to code interpretation problems, which can result in hard-to-locate bugs.

–u: Provides unbuffered stdout and stderr devices. Typically, the interpreter uses buffering to provide better application performance.

–v: Specifies that the interpreter should provide verbose output, which means that you can see everything going on in the background. You can also obtain this result by using PYTHONVERBOSE=x (where x is a True or False environment variable).

–V: Prints the version number and exits. This option is useful when you want to be sure you’re using the correct version of IronPython for your application.

–W arg: Defines the kind of warning control. Specifying these command line switches tells the interpreter to add the specified warning messages to the output.  You can use any of these values:

  • –Waction: Actions are one of the following strings: error (turns matching warnings into exceptions), ignore (never prints matching warnings), always (always prints matching warnings), default (prints the first occurrence of a warning for each location where the interpreter issues the warning), module (prints the first occurrence of a warning for each module where the error occurs), and once (prints only the first occurrence of a warning no matter where it appears).
  • –Wmessage: Messages are Regular Expressions that define which warning messages to match.
  • –Wcategory: Categories specify the class of the warning message.
  • –Wmodule: Modules are Regular Expressions that define which module to match.
  • –Wlineno: Line numbers are integer values that specify a line number to match. Using 0 matches all line numbers.

–x: Skips the first line of the source code, which may have special instructions that you don’t need for the current session.

Working with the –X: Command Line Switches

In addition to the standard command line switches, you also have access to the –X: command line switches, which configure the IronPython interpreter. The following list describes each of the configuration options:

–X:AutoIndent: Enables auto-indenting in the read-evaluation-print loop (REPL).

–X:ColorfulConsole: Enables ColorfulConsole support.

–X:Debug: Enables application debugging. This option is preferred over the –D command line switch because it’s newer and will enjoy a longer support period.

–X:EnableProfiler: Enables profiling support in the compiler, which helps you optimize your applications.

–X:ExceptionDetail: Enables ExceptionDetail mode, which gives you more information about every exception that occurs, making it easier to locate the source of the problem (but filling the screen much faster as well).

–X:Frames: Enables basic sys._getframe() support.

–X:FullFrames: Enables sys._getframe() with access to local objects and variables.

–X:GCStress: Specifies the garbage collector (GC) stress level. Stressing the GC can point out potential resource problems in your application.

–X:LightweightScopes: Generates optimized scopes that are easier for the GC to collect. Optimizing GC functionality tends to improve the overall performance (both speed and reliability) of your application.

–X:MaxRecursion: Determines the maximum recursion level within the application. Recursion can use a lot of system resources, so controlling the amount of recursion tends to reduce resource usage by applications that rely on recursion. Of course, reducing the recursion levels can also cause application exceptions.

–X:MTA: Runs the application in a multithreaded apartment (MTA).

–X:NoAdaptiveCompilation: Disables the adaptive compilation feature.

–X:PassExceptions: Tells the interpreter not to catch exceptions that are unhandled by script code.

–X:PrivateBinding: Enables binding to private members.

–X:Python30: Enables available Python 3.0 features, such as classic division (where dividing two integers produces an integer result).

–X:ShowClrExceptions: Displays the Common Language Specification (CLS) exception information.

–X:TabCompletion: Enables TabCompletion mode.

–X:Tracing: Enables support for tracing all methods even before the code calls sys.settrace().


Modifying the IPY.EXE Environment Variables

IPY also supports a number of environment variables. The following list describes each of these environment variables.

IRONPYTHONPATH: Specifies the path to search for modules used within an application

IRONPYTHONSTARTUP: Specifies the name and location of the startup module


Exiting the IronPython Interpreter

Eventually, you’ll want to leave the console. In order to end your session, simply type exit() and press Enter. As an alternative, you can always press Ctrl+Z and then Enter. The console will close.