Interacting with .NET Framework Elements

0
156

Now that you know how to get a .NET assembly loaded into IronPython, it’s time to consider where to go next. Of course, it’s not going to be possible to cover every potential destination in a single chapter of a book. However, the following sections provide some basics you can use to get started. For example, most developers need to know a little about the assemblies they have loaded, such as the version number. The following sections also show how to work with static methods and objects created from .NET classes. The final section provides a quick example that shows how to obtain a list of files and directories found in the root directory of your system. All these examples work together to help you get an idea of how .NET works within IronPython.

Obtaining Assembly Information

Developers will want to obtain information about the assemblies they load into IronPython. Part of the problem is going to be that you won’t see a list of these assemblies in Solution Explorer because Visual Studio doesn’t provide direct support for IronPython. Consequently, the application itself will need to have some level of assembly management support built into it. With this in mind, Listing 7-1 shows you how to perform some basic tasks with assemblies.

Listin g 7-1: Interacting with assemblies

[code]

# Add the .NET Framework 2.0 to the path.
import sys
sys.path.append(‘C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727’)
# Make clr accessible.
import clr
# Import the System assembly.
import System
# Add a reference for System.Xml and import it.
clr.AddReference(‘System.Xml.DLL’)
import System.Xml
# Display a list of available assemblies.
print ‘List of Assemblies:’
for ThisRef in clr.References:
print ThisRef
# Access a specific assembly and display more information about it.
ThisRef = clr.References[2]
print ‘nFull Name of System.Xml:’
print ThisRef.FullName
# Display the referenced assemblies.
print ‘nReferenced Assemblies:’
for Reference in ThisRef.GetReferencedAssemblies():
print Reference.ToString()
# Display the assembly attributes.
print ‘nAttributes:’
for AnAttribute in ThisRef.GetCustomAttributes(type(ThisRef)):
print AnAttribute.ToString()
# Pause after the debug session.
raw_input(‘Press any key to continue…’)

[/code]

The code begins by importing sys and adding the .NET Framework 2.0 path to sys.path. Adding just the path you need tends to reduce the risk of importing the wrong assembly. Even so, you want to verify that you’re using the right assembly, especially when the code is running on another system.

The next step is to import clr. This module provides the features required to interact with the assemblies. The next few lines of code import System and System.Xml so that you can see a number of assemblies in IronPython. Notice that the System.Xml import requires use of the clr.AddReference() method.

At this point, the example obtains the list of loaded assemblies from the clr.References property and displays them onscreen using a for loop. Figure 7-11 shows the list of assemblies for this example. Notice that the first assembly is mscorlib, which always loads.

You can drill down into an assembly as far as you want. The example continues by working with the System.Xml assembly. As a first step, the code displays the full name of the assembly. Using string manipulation, you can obtain the assembly name, version, culture, and public key token.

When creating an installation program, you often need to know the list of referenced assemblies. The next portion of application code shows how to perform this task using the ThisRef .GetReferencedAssemblies() method. The output includes the same four pieces of information as the assembly information, so you know precisely which assemblies to include with your application.

Some developers also want to know about attributes assigned to an assembly. The ThisRef .GetCustomAttributes(type(ThisRef)) method call obtains this information. You must provide the type of the assembly you want to interact with. Notice that the example uses the Python type() function, rather than a .NET equivalent. In some situations, you mix .NET and Python code to obtain a desired result. The code shows how to use a loop to obtain the list of attributes. Most assemblies include a wealth of attributes (some inherited). A developer might need to know some of these attributes, such as System.Security.Permissions.SecurityPermissionAttribute (which provides security information about the assembly), to create a functional application.

Figure 7-11: IronPython doesn’t limit the information you receive about assemblies.
Figure 7-11: IronPython doesn’t limit the information you receive about assemblies.

Working with the attributes can prove a little tricky because they each contain different values. When working with the AssemblyCompanyAttribute, for example, you can access the Company property that contains the name of the company that created the attribute. Of course, nothing differs from any other .NET language in this case. You need to know precisely which attributes you want to query and the properties within those attributes that contain the values you need in order to interact with attributes successfully.

Making Static Method Calls

Many of the tasks you perform using .NET require use of static methods. Static methods work the same in IronPython as they do in any .NET language. Listing 7-2 shows some static method calls that work with the current date and time. The techniques shown work with any static method.

Listin g 7-2: Performing tasks using static methods

[code]

# Add the .NET Framework 2.0 to the path.
import sys
sys.path.append(‘C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727’)
# Make clr accessible.
import clr
# Import the System assembly.
import System
# Get the system date and time.
CurrDateTime = System.DateTime.Now
# Display the date and time in a number of formats.
print ‘Short date and time:’
print System.DateTime.Now.ToShortDateString(),
print System.DateTime.Now.ToShortTimeString()
print ‘nLong date and time:’
print CurrDateTime.ToLongDateString(),
print CurrDateTime.ToLongTimeString()
# Display a few statistics.
print ‘n Date Statistics:’
print ‘Days in Month:’,
print CurrDateTime.DaysInMonth(CurrDateTime.Year, CurrDateTime.Month)
print ‘Daylight Savings?’, CurrDateTime.IsDaylightSavingTime()
print ‘Leap Year?’,
print CurrDateTime.IsLeapYear(CurrDateTime.Year)
# Manipulate the date.
print ‘nAdding a Day, Month, and Year:’
CurrDateTime = CurrDateTime.AddDays(1)
CurrDateTime = CurrDateTime.AddMonths(1)
CurrDateTime = CurrDateTime.AddYears(1)
print CurrDateTime.ToLongDateString()
# Pause after the debug session.
raw_input(‘Press any key to continue…’)

[/code]

The code begins by adding the required sys.path entry and importing the necessary modules and assemblies. It then creates a variable named CurrDateTime, which is only in place for convenience. The code sets CurrDateTime to reference System.DateTime.Now. You can do the same thing without relying on the variable.

The first outputs are the short and long date and time. Notice that the short date and time rely on System.DateTime.Now, while the long date and time rely on CurrDateTime. In both cases, the code calls on static methods to output the date and time in a specific format using ToShortDateString(), ToShortTimeString(), ToLongDateString(), and ToLongTimeString(). Figure 7-12 shows the output from these calls.

Figure 7-12: Static methods enable you to perform tasks without creating objects.
Figure 7-12: Static methods enable you to perform tasks without creating objects.

As with any date and time example, you can output statistics for the date and time in question. The example shows how to determine the number of days in the month, whether daylight savings time is in effect, and whether this is a leap year. Notice that some of these calls also require that you provide property values to obtain the output. You could just as easily replace CurrDateTime with System.DateTime.Now for the properties.

You do need a variable to hold date and time manipulations. The method calls are still static, but when you add date or time values, you need a place to store the result. The final portion of the example shows how you’d perform this task. The output is one day, one month, and one year later than the current date.

Creating .NET Objects

The .NET Framework provides access to a lot of objects and following chapters will explore many of them. However, one of the objects that developers need to know about first is the exception. The .NET code you run will generate exceptions at times, and Python does provide support for them as long as you have some idea of what to expect. In fact, you can even create and catch .NET exceptions in your IronPython code, as shown in Listing 7-3.

Listin g 7-3: Catching and handling .NET exceptions

[code]

# Add the .NET Framework 2.0 to the path.
import sys
sys.path.append(‘C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727’)
# Make clr accessible.
import clr
# Import the System assembly.
import System
# Create an exception.
ThisException = System.OperationCanceledException(‘The User Said No!’)
# Ask the user a question.
try:
Answer = raw_input(‘Do you want to continue? (Y/N)‘)
# Check the response.
if Answer.upper() == ‘Y’:
print ‘Great!’
else:
raise(ThisException)
except SystemError as (SysErr):
print ‘nMessage:’, SysErr.message
print ‘nClass:’, SysErr.clsException.GetType()
print ‘nClass, Message, and Stack Trace:’, SysErr.clsException
# Pause after the debug session.
raw_input(‘Press any key to continue…’)

[/code]

The example starts out as most do in the chapter by making the appropriate references and importing the correct modules and assemblies. The first bit of code creates an exception, ThisException, by calling the System.OperationCanceledException() constructor. You can embed previous exceptions in the current exception by using the correct constructor, but the example uses just one level to keep things simple.

The code then asks the user a simple question. If the user answers N, the code raises an exception and then catches it as a SystemError. Notice that this exception handler provides a means of accessing the error through SysErr. The easiest way to obtain the error message is through the SysErr.message.

Of course, you’ll probably want more information. All of the .NET errors will appear as the SystemError type. Consequently, you need to consider how to detect the proper error class in your IronPython code. The SysErr.clsException.GetType() provides the answer. You can also display a complex message by displaying the SysErr.clsException attribute. Figure 7-13 shows the output from this example.

Figure 7-13: Use SysErr.clsException.GetType () to obtain an error class.
Figure 7-13: Use SysErr.clsException.GetType () to obtain an error class.

Creating the Directory Example

You’ll probably find that you need access to the user’s hard drive at some point. IronPython does provide the functionality that Python provides for working with drives, directories, and folders, but many developers will find using the .NET functionality easier — especially if that’s what they normally rely upon. Listing 7-4 shows a very simple example of gaining access to directories and files. Once you gain this access, you can perform any task that you’d normally perform with a directory or file. The rest of System.IO works amazingly like what you’d expect from any .NET language.

Listin g 7-4: Obtaining access to directories and files

[code]

# Add the .NET Framework 2.0 to the path.
import sys
sys.path.append(‘C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727’)
# Make clr accessible.
import clr
# Import the required assemblies.
import System
import System.IO
# Get the starting directory.
Start = raw_input(‘Type a starting directory (such as C:\)‘)
# Create the DirectoryInfo object.
MyDir = System.IO.DirectoryInfo(Start)
# Display a list of subdirectories.
print ‘Subdirectories:’
for EachDir in MyDir.GetDirectories():
print EachDir, ‘t’,
# Display a list of files.
print ‘nnFiles:’
for EachFile in MyDir.GetFiles():
print EachFile, ‘t’,
# Pause after the debug session.
raw_input(‘nPress any key to continue…’)

[/code]

The code begins with the usual imports. Notice that you must import the System.IO assembly to make this example work.

At this point, the code asks the user to provide a drive specification as a starting point. You can type any location on your hard drive that actually exists. The example doesn’t provide error-trapping code for the sake of clarity

Now that the code has a drive specification to use, it creates a System.IO.DirectoryInfo() object, MyDir, just as you would when using a .NET language. The code uses MyDir to access the list of directories using MyDir.GetDirectories() and a list of files using MyDir.GetFiles(). In this case, the code simply prints out the result, but you could go on to process the directories and files. Figure 7-14 shows typical output from this example (of course, the actual directory and filenames will match your system).

Figure 7-14: A list of directories and subdirectories is in the C: folder
Figure 7-14: A list of directories and subdirectories is in the C: folder