Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / IronPython

Beginning IronPython

5.00/5 (1 vote)
10 Jul 2013CPOL4 min read 19.4K  
An intro to IronPython.

Introduction

Okay, so you’ve read the chapter on IronPython syntax. Brilliant, learning a new programming language is easy! You feel like such a polyglot. What’s all the fuss about?  All that remains now is a few formalities. Install the framework and knock out a quick app to demonstrate how easy it is. The only problem is that nothing works and the error messages make no sense.

Back to the world of the programming beginner.

You need to learn a few practical lessons before you can say that you are a competent Python programmer. It is important to be able to interpret the common error messages and structure your project.  Normally you will find that the official documents will gloss over this stuff because they like to leave it to your discretion. As a result you will find yourself searching the internet for a blog to help!

  • You can execute from the command line with ipy.exe, use the IronPython Console or the VS Tools.

Example, calling C# code from IronPython

Use IronPython to create some tests/specifications; one static .NET CLR class and one normal .NET CLR class. The classes will be contained in an assembly project called Polyglot, as we want to use multiple programming languages in this example.

  • Greet static class. This will have one method and one property. The method accepts a parameter, a name, and the returns a greeting for that name, e.g. “Hello Jon”. The property simply returns a string “Hello World!”.
  • Math class. This class deals with simple arithmetic, does not handle negative numbers maintains a list of answers. It has Add and Subtract methods and the Subtract method throws an exception if it cannot return a positive number. It also has an array containing all the results with the most recent result at the beginning of the list.

RunTests.py 

Python
  1  import sys
  2  import unittest
  3  import clr
  4  sys.path.Add('C:\\sut') # folder containing software to be tested
  5  clr.AddReferenceToFile('Polyglot.dll')
  6  
  7  from Polyglot import Greet
  8  
  9  class GreetTest(unittest.TestCase):
 10      softwareUnderTest = Greet
 11      def testGreet_ShowCsGreeting_GreetWithName(self):     
 12          self.assertEquals('Hello Brian', self.softwareUnderTest.GreetMe('Brian'), 'Greet Me test')        
 13      def testGreet_ShowCsGreeting_GreetHello(self):  
 14          self.assertEquals('Hello World!', self.softwareUnderTest.Hello, 'Greet Hello test')
 15  
 16  from Polyglot import Math
 17  
 18  class MathTest(unittest.TestCase):
 19      softwareUnderTest = Math()
 20      def testMath_Add_Simple(self):
 21          self.assertEquals(3, self.softwareUnderTest.Add(1,2), 'Simple Add')
 22      def testMath_Subtract_Simple(self):
 23          self.assertEqual(3, self.softwareUnderTest.Subtract(5,2), 'Simple Subtract')
 24      def testMath_Subtract_NegativeResultFails(self):
 25          with self.assertRaises(ValueError):
 26              self.softwareUnderTest.Subtract(3, 4)
 27      def testMath_Results_IsSetAndOrdered(self):
 28          result1 = 2
 29          result2 = 3
 30          result3 = 4
 31          self.softwareUnderTest = Math()
 32          self.assertEqual(0, len(self.softwareUnderTest.Results)) # to begin with there are no results
 33          self.softwareUnderTest.Add(1,1)
 34          self.assertEqual(1, len(self.softwareUnderTest.Results)) # after one operation there will be one result
 35          self.assertEqual(result1, self.softwareUnderTest.Results[0]) # check the result
 36  
 37          # run a couple more operations and check they are stored propery
 38          self.softwareUnderTest.Subtract(5,2)
 39          self.softwareUnderTest.Add(2,2)
 40          self.assertEqual(result3, self.softwareUnderTest.Results[0])
 41          self.assertEqual(result2, self.softwareUnderTest.Results[1])
 42          self.assertEqual(result1, self.softwareUnderTest.Results[2])
 43  
 44  try:
 45      if __name__ == '__main__':
 46          unittest.main()
 47  except:
 48      e = sys.exc_info()[0]
 49      print( "Error: %s" % e )
 50      clr.ClearProfilerData() # unload the .dll file so the file lock is released
 51  
 52  a=raw_input('The end!')  

 

These are the C# classes that have been specified by the preceding test. You will just need to create a C# Class Library project. In the project properties under Build Events, add the following code to the Post Build Event command line:

copy $(TargetPath) C:\sut
copy $(TargetDir)$(TargetName).pdb C:\sut

Greet.cs

C#
namespace Polyglot
{
    public static class Greet
    {
        public static string GreetMe(string name)
        {
            return string.Format("Hello {0}", name);
        }

        public static string Hello { get { return "Hello World!"; } }
    }
}

Math.cs

C#
using System.Collections.Generic;

namespace Polyglot
{
    public class Math
    {
        List _results;
        public Math()
        {
            _results = new List();
        }

        public uint Add(uint x, uint y)
        {
            return lastResult = x + y;
        }

        public uint Subtract(uint x, uint y)
        {
            if (y > x)
                throw new System.ArgumentException("Operation would result in a negative result");

            return lastResult = x - y;
        }

        private uint lastResult
        {
            set
            {
                _results.Insert(0, value);
            }
        }

        public uint[] Results
        {
            get { return _results.ToArray(); }
        }
    }
} 

Points to Note 

  1. line 2: import unittest
    Use the PyTest default frameworks which is similar to NUnit in .NET.
  2. line 4: sys.path.Add('C:\\sut')
    We have added a directory to the system paths. This is where I have stored to Polyglot.dll will be tested.
  3. line 5: clr.AddReferenceToFile('Polyglot.dll')
    Add a reference to Polyglot assemble so it can be called via the CLR.
  4. line 7: from Polyglot import Greet
    Specify that the Greet class in the Polygot namespace will be used. There is no equivalent command in C# because C# intrinically uses all the types in a namespace, i.e. using namespace.
  5. line 9: class GreetTest(unittest.TestCase):
    Brackets are used to inherit from a class
  6. line 10: softwareUnderTest = Greet
    A reference to the C# Greet class type has been created. This is a static class so we can call methods on the class by call the methods directly from the type reference.
  7. line 19: softwareUnderTest = Math()
    An instance of the C# Math class has been created. The new keyword is not required like in C# however we must remember to use brackets.
  8. Method definitions & self. All class level variables, methods and types are referenced with self.
  9. Indentation and white-space are important. Python uses these instead of the {} in C based languages.
  10. line 46: unittest.main() Used to execute the unit tests.

Common Errors

It is all very well and good saying, avoid these mistakes but it would be better to know how to fix the mistakes when you make them. Let us see what happens if we introduce some typical beginner mistakes.

  1. line 2: import unittest, when it is removed:

    NameError: global name ‘unittest’ is not defined

  2. line 4: sys.path.Add('C:\\sut') , when it is removed:

    System.IO.IOException: Could not add reference to assembly Polygot.dll

  3. line 5: clr.AddReferenceToFile('Polyglot.dll'), when it is removed:

    TypeError: No module name Polygot

  4. line 7: from Polyglot import Greet, when it is removed:

    NameError: global name ‘Greet’ is not defined

  5. line 9: class GreetTest(unittest.TestCase): If the ‘:‘ is missing:

    SyntaxError: Unexpected token ‘newline’

  6. line 10: softwareUnderTest = Greet If brackets are accidentally added:

    Cannot create instances of Greet because it is abstract

  7. line 19: softwareUnderTest = Math() If the () is missing:

    TypeError: Subtract takes exactly 3 arguments (2 given)

    In Python the first parameter is always the class instance so it is expecting an extra parameter; Math.Subtract(Math(),2,1) would work.

  8. Method definitions & self.

    TypeError: testMath_Add_Simple() takes no arguments (1 given)

  9. Indentation and white-space are important. It can cause all sorts of errors:

    IndentationError: unindent does not match any other indentation level

    IndentationError: unexpected indent

  10. line 46: unittest.main() No tests would execute without it.

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)