Sunday, November 22, 2009

WCF Service in pure IronPython with config file

I was wrong when I wrote in the last post that the IronPython service cannot be saved into an assembly. It can. Which opens a way to use .config file to configure the service.

This is a simple config file for the service:

ConfigService.exe.config

<?xml version="1.0"?>
<configuration>
<system.serviceModel>
    <services>
      <service name="ConfigService.myService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9000/myWcfService"/>
          </baseAddresses>
        </host>
        <endpoint address=""
            binding="basicHttpBinding"
            contract="TestServiceInterface.ImyService"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

The interface is the same as in the previous version. The only difference in the service to the previous version is in the ServiceHost initialization - we omit the service configuration parameters because they are in the .config file. I also changed the clr namespace:

ConfigService.py

import clr
import clrtype
clr.AddReference('System.ServiceModel')
from TestServiceInterface import ImyService
from System import Console, Uri
from System.ServiceModel import (ServiceHost,
        BasicHttpBinding, ServiceBehaviorAttribute,
        InstanceContextMode)

class myService(ImyService):
    __metaclass__ = clrtype.ClrClass
    _clrnamespace = "ConfigService"
    _clrclassattribs = [ServiceBehaviorAttribute]

    def GetData(self, value):
        return "IronPython config service: You entered: %s" % value

sh = ServiceHost(myService)
sh.Open()
Console.WriteLine("Press  to terminate\n")
Console.ReadLine()
sh.Close()

If you want to run this script, you must save the ConfigService.exe.config as ipy.exe.config to the folder with the IronPython interpreter ipy.exe.

To save the service as an assembly, run the following command:

C:\IronPython-2.6\ipy.exe C:\IronPython-2.6\Tools\Scripts\pyc.py  /out:ConfigService /target:exe /main:ConfigService.py clrtype.py TestServiceInterface.py

The ConfigService.dll and ConfigService.exe are created. Add the ConfigService.exe.config to the same folder and when you run ConfigService.exe, the service starts. Note you also need all IronPython .dlls in the same folder.

You can adjust the .config file to expose a MEX endpoint (ConfigService.mex.exe.config) but I don't see a big point in it because svcutil.exe generates C# or VB code. Anyway - here are the generated files: myService.cs, myService.config

You can run the old TestClient.py and it will successfully retrieve value from the service. But the old TestClient.py does not use .config file. If we want to use .config file for the client, we have to rewrite the WCF client. First, here is the sample client .config file:

ConfigClient.exe.config

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <client>
        <endpoint address="http://localhost:9000/myWcfService"
            binding="basicHttpBinding"
            contract="TestServiceInterface.ImyService"/>
    </client>
  </system.serviceModel>
</configuration>

You can see it is very similar to the generated one. We do not specify details of the binding but we specify full name of the contract interface.

If you check the generated client proxy class by svcutil.exe, you see it is based on System.ServiceModel.ClientBase and the interface ImyService. There are some empty constructors and all methods from ImyService interface return result of the same method name call on Channel property. That's why I have created WcfClient helper function. The client source then looks like the following:

ConfigService.py

import clr
clr.AddReference('System.ServiceModel')
import System.ServiceModel
from TestServiceInterface import ImyService

def WcfClient(interface):

    class WcfClientBase(System.ServiceModel.ClientBase[interface]):

        def __getattr__(self, name):
            # if name is method from interface, return the Channel method
            if name in (k[0] for k in interface.emitted_methods.keys()):
                return getattr(self.Channel, name)

    return WcfClientBase()

wcfcli = WcfClient(ImyService)
print "WCF config client returned:\n%s" % wcfcli.GetData(11)

The WcfClient helper function returns an instance of class based on System.ServiceModel.ClientBase. The __getattr__ checks if the requested attribute name is interface method and if so, it returns the Channel's method with the same name. Which is the same behavior as the generated client proxy class in couple of lines of code.

To save the client as an assembly, run the following command:

C:\IronPython-2.6\ipy.exe C:\IronPython-2.6\Tools\Scripts\pyc.py /out:ConfigClient /target:exe /main:ConfigClient.py clrtype.py TestServiceInterface.py

The ConfigClient.dll and ConfigClient.exe are created. Add the ConfigClient.exe.config to the same folder and when you run ConfigClient.exe, the client calls the service.

Having this I think there is only a small step to use the IronPython WCF services in IIS. Unfortunately, I do not know how to do it...

Tuesday, November 17, 2009

WCF Service in pure IronPython

I wrote about implementing WCF service in IronPython a couple of weeks ago. Meanwhile I pushed Shri a little bit with the clrtype.py and he has implemented ClrInterface metaclass there so we can create the whole WCF service in IronPython now.

The IronPython interface implementation is straightforward:

TestServiceInterface.py

import clr
import clrtype
clr.AddReference('System.ServiceModel')
from System.ServiceModel import (
        ServiceContractAttribute,
        OperationContractAttribute)
OperationContract = clrtype.attribute(
        OperationContractAttribute)

class ImyService(object):
    __metaclass__ = clrtype.ClrInterface
    _clrnamespace = "TestServiceInterface"
    _clrclassattribs = [ServiceContractAttribute]

    @OperationContract()
    @clrtype.accepts(int)
    @clrtype.returns(str)
    def GetData(self, value):
        raise RuntimeError("this should not get called")

Also switching from C# interface to IronPython interface is easy:

TestService.py

import clr
import clrtype
clr.AddReference('System.ServiceModel')
from TestServiceInterface import ImyService
from System import Console, Uri
from System.ServiceModel import (ServiceHost,
        BasicHttpBinding, ServiceBehaviorAttribute,
        InstanceContextMode)

class myService(ImyService):
    __metaclass__ = clrtype.ClrClass
    _clrnamespace = "myWcfService"
    _clrclassattribs = [ServiceBehaviorAttribute]

    def GetData(self, value):
        return "IronPython: You entered: %s" % value

sh = ServiceHost(myService, Uri(
        "http://localhost:9000/myWcfService"))
sh.AddServiceEndpoint(clr.GetClrType(ImyService),
        BasicHttpBinding(), "")
sh.Open()
Console.WriteLine("Press  to terminate\n")
Console.ReadLine()
sh.Close()

Notice that we call ServiceHost with myService which is the type and not the instance of our service. Because of this, the ServiceBehavior attribute does not need to have InstanceContextMode.Single parameter.

Finally, here is the test client:

TestClient.py

import clr
clr.AddReference('System.ServiceModel')
import System.ServiceModel
from TestServiceInterface import ImyService

mycf = System.ServiceModel.ChannelFactory[ImyService](
        System.ServiceModel.BasicHttpBinding(),
        System.ServiceModel.EndpointAddress(
            "http://localhost:9000/myWcfService"))
wcfcli = mycf.CreateChannel()
print "WCF service returned:\n%s" % wcfcli.GetData(11)

The disadvantage of having just a single service instance is gone, the harder configuration remains. One new disadvantage can be it is not possible (yet) to compile the interface and save it to disk nor use it from other .NET languages.

Edit 22. 11. 2009: See WCF Service in pure IronPython with config file

Monday, November 16, 2009

INotifyPropertyChanged and databinding in Silverlight

In the previous article, I wrote about IronPython and databinding in WPF applications. The last note was it does not work in Silverlight. Thanks to Shri Borde (IronPython/IronRuby dev lead) who updated clrtype module, the note is not true any more.

Let's create a small Silverlight app in IronPython from scratch. I use IronPython 2.6 RC2. Follow http://lists.ironpython.com/pipermail/users-ironpython.com/2009-October/011543.html to avoid bugs in IronPython 2.6 RC2.

Create a new project:

C:\IronPython-2.6\Silverlight\script\sl.bat python BindTest

Change the app.xaml to

<usercontrol x:Class="System.Windows.Controls.UserControl"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <stackpanel x:Name="DataPanel"
        Orientation="Horizontal">
        <textblock Text="Size"/>
        <textblock Text="{Binding size}"/>
        <textbox x:Name="tbSize"
            Text="{Binding size, Mode=TwoWay}" />
        <button x:Name="Button"
            Content="Set Initial Value"></Button>
    </StackPanel>
</UserControl>

The difference comparing to WPF version is we have to specify binding mode because the default mode for TextBox in Silverlight is OneWay. And we cannot use UpdateSourceTrigger=PropertyChanged because Silverlight does not have such UpdateSourceTrigger.

Silverlight binding is limited comparing to WPF. That's why we have to create CLR properties to Silverlight be able to see them. DevHawk has a nice serie about clr types on his blog.

Creating CLR property with clrtype.py is easy. Shri described it on IronPython mailing list. Because I use my enhanced @notify_property decorator, I can write:

class ViewModel(NotifyPropertyChangedBase):
    __metaclass__ = clrtype.ClrClass
    _clrnamespace = "BindTest"
    
    def __init__(self):
        super(ViewModel, self).__init__()
        # must be string to two-way binding work
        # correctly
        self.size = '10'

    @notify_property
    @clrtype.returns(str)
    def size(self):
        return self._size

    @size.setter
    @clrtype.accepts(str)
    def size(self, value):
        self._size = value
        print 'Size changed to %r' % self.size

The NotifyPropertyChangedBase class is the same as for WPF version. The enhanced @notify_property decorator calls automatically clrtype.accepts() for getter and clrtype.returns() for setter so we do not need to call them manually for every property:

class notify_property(property):

    def __init__(self, getter):
        def newgetter(slf):
            #return None when the property does not
            # exist yet
            try:
                return getter(slf)
            except AttributeError:
                return None
        getter = clrtype.accepts()(getter)
        clrtype.propagate_attributes(getter, newgetter)
        super(notify_property, self).__init__(newgetter)

    def setter(self, setter):
        def newsetter(slf, newvalue):
            # do not change value if the new value is
            # the same, trigger PropertyChanged event
            # when value changes
            oldvalue = self.fget(slf)
            if oldvalue != newvalue:
                setter(slf, newvalue)
                slf.OnPropertyChanged(setter.__name__)
        setter = clrtype.returns()(setter)
        clrtype.propagate_attributes(setter, newsetter)
        return property(
            fget=self.fget,
            fset=newsetter,
            fdel=self.fdel,
            doc=self.__doc__)

Then App looks similarly to the WPF counterpart:

class App:
    def __init__(self):
        self._vm = ViewModel()
        self.root = Application.Current.LoadRootVisual(
                UserControl(), "app.xaml")
        self.DataPanel.DataContext = self._vm
        self.Button.Click += self.OnClick

    def OnClick(self, sender, event):
        # must be string to two-way binding work
        # correctly
        self._vm.size = '10'

    def __getattr__(self, name):
        # provides easy access to XAML elements
        # (e.g. self.Button)
        return self.root.FindName(name)

a = App()

Run Chiron with the BindTest app

C:\IronPython-2.6\Silverlight\script\sl.bat python BindTest

and check the application in the browser on http://localhost:2060/index.html.

Whatever you write into the text box appears in the label in front of the text box when the text box loses the focus. When you click the button, the value is reseted. You can also change the value from the console:

a._vm.size= '3'

Download app.xaml and app.py. You also need clrtype.py and pyevent.py (from C:\IronPython-2.6\Tutorial\pyevent.py) in the BindTest folder.

Wednesday, November 11, 2009

INotifyPropertyChanged and databinding in IronPython WPF

INotifyPropertyChanged is important interface for building WPF or Silverlight applications using M-V-VM concept (MSDN article).

In simple language, you have a Model which provides access to your data (e.g in database, files, web, etc.). Then you have a ViewModel that access data in the Model via Model's interface and provides data to a View which is XAML file with UI layout. Linkage between ViewModel and View is done by binding that utilizes PropertyChanged event to properly update all UI elements.

I have found two examples how to implement INotifyPropertyChanged interface in IronPython. The first one uses __setattr__ hook. Personally, I don't like it - it is not clear and easily readable code. The second one is better because it uses properties. But you have to write self.OnPropertyChanged("my_property_name") for every property. Not ideal.

That's why I sit down and write a notify_property:

class notify_property(property):

    def __init__(self, getter):
        def newgetter(slf):
            try:
                return getter(slf)
            except AttributeError:
                return None
        super(notify_property, self).__init__(newgetter)

    def setter(self, setter):
        def newsetter(slf, newvalue):
            oldvalue = self.fget(slf)
            if oldvalue != newvalue:
                setter(slf, newvalue)
                slf.OnPropertyChanged(setter.__name__)
        return property(
            fget=self.fget,
            fset=newsetter,
            fdel=self.fdel,
            doc=self.__doc__)

With this subclass I aimed several goals:

  • usage simple as @property decorator (actualy no other usage is possible as I implemented __init__ with just one parameter that must be the getter)
  • when property is on yet defined, it should return None
  • automaticaly handle PropertyChanged event when and only when property has changed

We also need to implement INotifyPropertyChanged interface in IronPython so we can call OnPropertyChanged method. See Overiding events in IronPython\Doc\dotnet-integration.rst to understand what means add_ and remove_ methods.

class NotifyPropertyChangedBase(INotifyPropertyChanged):
    PropertyChanged = None

    def __init__(self):
        self.PropertyChanged, self._propertyChangedCaller = pyevent.make_event()

    def add_PropertyChanged(self, value):
        self.PropertyChanged += value

    def remove_PropertyChanged(self, value):
        self.PropertyChanged -= value

    def OnPropertyChanged(self, propertyName):
        if self.PropertyChanged is not None:
            self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))

Now we can implement a simple class with properties with change notification:

class DataObject(NotifyPropertyChangedBase):
    
    def __init__(self, size):
        super(DataObject, self).__init__()
        self.size = size

    @notify_property
    def size(self):
        return self._size

    @size.setter
    def size(self, value):
        self._size = value

You can see it is very easy - just like any other property in Python.

Finaly, let's put all together. When you run the code below, it shows a window with label, textbox and button. The label is updated as you type into the textbox and a message is written into the console as well. By default, the textbox is updated when it looses focus, so I have to change UpdateSourceTrigger to PropertyChanged. When you click the button, the value is reset. Note if you use type int instead of string the two-way bindign would not work.

notpropwpf.py

import clr
import System
clr.AddReference('PresentationFramework')
clr.AddReference('PresentationCore')

from System.Windows.Markup import XamlReader
from System.Windows import Application, Window
from System.ComponentModel import INotifyPropertyChanged, PropertyChangedEventArgs
import pyevent

XAML_str = """<window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="250" Height="62">
    <stackpanel x:Name="DataPanel" Orientation="Horizontal">
        <label Content="Size"/>
        <label Content="{Binding size}"/>
        <textbox x:Name="tbSize" Text="{Binding size, UpdateSourceTrigger=PropertyChanged}" />
        <button x:Name="Button" Content="Set Initial Value"></Button>
    </StackPanel>
</Window>"""

class notify_property(property):

    def __init__(self, getter):
        def newgetter(slf):
            #return None when the property does not exist yet
            try:
                return getter(slf)
            except AttributeError:
                return None
        super(notify_property, self).__init__(newgetter)

    def setter(self, setter):
        def newsetter(slf, newvalue):
            # do not change value if the new value is the same
            # trigger PropertyChanged event when value changes
            oldvalue = self.fget(slf)
            if oldvalue != newvalue:
                setter(slf, newvalue)
                slf.OnPropertyChanged(setter.__name__)
        return property(
            fget=self.fget,
            fset=newsetter,
            fdel=self.fdel,
            doc=self.__doc__)

class NotifyPropertyChangedBase(INotifyPropertyChanged):
    PropertyChanged = None

    def __init__(self):
        self.PropertyChanged, self._propertyChangedCaller = pyevent.make_event()

    def add_PropertyChanged(self, value):
        self.PropertyChanged += value

    def remove_PropertyChanged(self, value):
        self.PropertyChanged -= value

    def OnPropertyChanged(self, propertyName):
        if self.PropertyChanged is not None:
            self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))

class ViewModel(NotifyPropertyChangedBase):
    
    def __init__(self):
        super(ViewModel, self).__init__()
        # must be string to two-way binding work correctly
        self.size = '10'

    @notify_property
    def size(self):
        return self._size

    @size.setter
    def size(self, value):
        self._size = value
        print 'Size changed to %r' % self.size

class TestWPF(object):

    def __init__(self):
        self._vm = ViewModel()
        self.root = XamlReader.Parse(XAML_str)
        self.DataPanel.DataContext = self._vm
        self.Button.Click += self.OnClick
        
    def OnClick(self, sender, event):
        # must be string to two-way binding work correctly
        self._vm.size = '10'

    def __getattr__(self, name):
        # provides easy access to XAML elements (e.g. self.Button)
        return self.root.FindName(name)

tw = TestWPF()
app = Application()
app.Run(tw.root)

You need pyevent.py from IronPython\Tutorial\ folder to run to example.

Unfortunately, this does not work in Silverlight, probably because the property is not .NET field. See next atricle for Silverlight version.

Friday, October 30, 2009

WCF Service in IronPython

Edit 17. 11. 2009: See the article about WCF service in pure IronPython.

Until IronPython 2.6, it was not possible to create WCF service host in pure IronPython. The closest way was to create stub in C# and subclass it in IronPython or create the whole service in C# and run it from IronPython. It is now much simpler with IronPython 2.6 although you still have to write a little C# code.

Simple WCF service implemented in C# looks like this:

TestServiceInterface.cs

using System;
using System.ServiceModel;

namespace TestServiceInterface
{
    [ServiceContract]
    public interface ImyService
    {
        [OperationContract]
        string GetData(int value);
    }
}

TestService.cs

using System;
using System.ServiceModel;
using TestServiceInterface;

namespace myWcfService
{
    public class myService : ImyService
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
    }

    public class mySvc
    {
        public static void Main()
        {
            ServiceHost sh = new ServiceHost(
                typeof(myService),
                new Uri("http://localhost:9000/myWcfService"));
            sh.AddServiceEndpoint(
                typeof(ImyService),
                new BasicHttpBinding(),
                "");
            sh.Open();
            Console.WriteLine("Press  to terminate\n");
            Console.ReadLine();
            sh.Close();
        }
    }
}

You build it:

csc /target:library TestServiceInterface.cs
csc /r:TestServiceInterface.dll TestService.cs

The reason I put TestServiceInterface into separate file is that you cannot create interfaces in IronPython. So this is the only part written in C# when implementig WCF service in IronPython.

The implementation then looks like this:

TestService.py

import clr
import clrtype
clr.AddReference('System.ServiceModel')
clr.AddReference('TestServiceInterface')
from TestServiceInterface import ImyService
from System import Console, Uri
from System.ServiceModel import (ServiceHost, BasicHttpBinding,
        ServiceBehaviorAttribute, InstanceContextMode)
ServiceBehavior = clrtype.attribute(ServiceBehaviorAttribute)

class myService(ImyService):
    __metaclass__ = clrtype.ClrMetaclass
    _clrnamespace = "myWcfService"
    _clrclassattribs = [
            ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

    def GetData(self, value):
        return "IronPython: You entered: %s" % value

sh = ServiceHost(
        myService(),
        Uri("http://localhost:9000/myWcfService")
    )
sh.AddServiceEndpoint(
        clr.GetClrType(ImyService),
        BasicHttpBinding(),
        "")
sh.Open()
Console.WriteLine("Press  to terminate\n")
Console.ReadLine()
sh.Close()

The myService class must have InstanceContextMode.Single ServiceBehavior attribute because we are passing service instance to the ServiceHost constructor. This is done via new __clrtype__ metaclass. See the error if we don't use the attribute. I was not able to pass type into the ServiceHost constructor.

To test the service, you can use C# or IronPython client implementation:

TestClient.cs

using System;
using System.ServiceModel;
using TestServiceInterface;

namespace myWcfClient
{
    public class cli
    {
        public static void Main()
        {
   ChannelFactory mycf = new ChannelFactory(
     new BasicHttpBinding(),
        new EndpointAddress("http://localhost:9000/myWcfService"));
   ImyService wcfcli = mycf.CreateChannel();
   Console.WriteLine("Calling GetData(33) returns:\n{0}", wcfcli.GetData(33));
        }
    }
}

TestClient.py

import clr
clr.AddReference('System.ServiceModel')
import System.ServiceModel
clr.AddReference('TestServiceInterface')
from TestServiceInterface import ImyService

mycf = System.ServiceModel.ChannelFactory[ImyService](
        System.ServiceModel.BasicHttpBinding(),
        System.ServiceModel.EndpointAddress("http://localhost:9000/myWcfService"))
wcfcli = mycf.CreateChannel()
print "WCF service returned:\n%s" % wcfcli.GetData(11)

Disadvantages:

  • You can have only single instance of the service because you are passing the service instance instead of service type.
  • You cannot easily use .config file to configure your service.

Thursday, September 24, 2009

How to clone VirtualBox virtual machine

VirtualBox is great piece of software for virtualization. I like it more than VMWare or VirtualPC. The downside of it is its lack of easy cloning or copying capabilities. There are none. And because everything in VirtualBox has UUID (guid), pure file copy does not work well.

All advices I have seen were about: create the new virtual machine manually, clone HDD .vdi file with  VBoxManage clonevdi command and attach it to the newly created virtual machine. Manually!?

That's why I've created a simple Python script that cares about exporting and importing virtual machines (Thanks for the VirtualBox 3 SDK!). When exporting, you can select the virtual machine and snapshot you want to export:

The exported machines are stored in exp folder at the script file. The time stamp is added to the machine name for unique identification. When importing, you are offered with the saved virtual machines and you simply choose one. Of course you can copy the exported machine to different computer (having the same VirtualBox versions is recommended).

The script is very simple and targeted to my needs. That means it exports only primary HDD and network adapter 0. It does not export CD/DVD-ROM, Floppy nor Serial ports.

Try it and let me know whether it's helpful: download script (it requires ConfigObj 4).

Update 1. 10. 2009: I struggled running the script on my new Win 7 64-bit system. It complained class is not registered for VirtualBox.Session. The reason was mixing 32-bit and 64-bit programs - see the explanation. If you use 64-bit OS, you have to have installed 64-bit version of Python and pywin32!

Update 11. 11. 2009: I have updated the script to better serve my needs. For example, when restoring virtual machine, you can enter a new name for it. Be carefull when restoring one saved machine to two new ones as you have to chagne MAC address manually.

Unfortunately, the old config file is not compactible with the new version. But I think you can guess from the Python exception what is wrong with the config file and fix it. The old version is still available.

Update 29. 12. 2009: When I upgraded to VirtualBox 3.1, I received KeyError when I run my script ({2158464A-F706-414B-A8C4-FB589DFC6B62}). To get rid of it, delete all from from \Python26\Lib\site-packages\win32com\gen_py\ except __init__.py.

Saturday, May 16, 2009

Pycon 2009: Functional Testing of Desktop Applications

Here is a link to Michael Foord talk at Pycon 2009 in Chicago about functional testing of desktop applications:

Functional Testing of Desktop Applications
Many advocates of unit testing believe that testing desktop (GUI) applications is so difficult as to not be worth it. Not only is it possible, but 'functional testing' (testing an application from the point of view of the user) is an important part of an agile development process.

I watched it yesterday and it is very good!

Friday, May 15, 2009

Testing an unknown application

From time to time you may need to test an unknown application. I have encounter it when I needed to test our installation program. The task was simple - install the application for automated smoke tests. In such cases I gladly return to Accessibility.

Let's pretend our testing application is not written in .NET and the only way how to explore it is through the accessibility (AccExplorer):

All we need to do is to access Accessibility objects from IronPython. There is a project called Managed Windows API that nicely wraps accessibility for .NET. It also wraps other Win32 API calls (mouse clicks etc.) but I stay with Win32API.dll because of my laziness :-).

Utilizing the Managed Windows API you can control the accessibility objects. Here is the snippet:

import clr
# Win32API provide access to Win32 API functions
clr.AddReference('Win32API')
from Win32API import Win32API
# ManagedWinapi provide access to Accessibility objects
clr.AddReference('ManagedWinapi')
import ManagedWinapi.Accessibility as ma
import ManagedWinapi.Windows as mw

def GetGUIATWindow():
   """ Return GUIAT_PoC window accessibility object. """
   def callback(aWindow):
       return aWindow.Title == 'GUIAT - Proof of Concept'
   guiat_window = mw.SystemWindow.FilterToplevelWindows(callback)
   # assume guiat_window is list with just one object
   return ma.SystemAccessibleObject.FromWindow(guiat_window[0],
       ma.AccessibleObjectID.OBJID_WINDOW)

guiat_acc = GetGUIATWindow()
# position of the 'New listbox item' text box
pos = guiat_acc.Children[3].Children[1].Location
# focus the text box
Win32API.MouseClick(pos.X + pos.Width/2, pos.Y + pos.Height/2)
Win32API.SendString('Accessibility test')
# position of the 'Add Item' button
pos = guiat_acc.Children[3].Children[2].Location
# click the button
Win32API.MouseClick(pos.X + pos.Width/2, pos.Y + pos.Height/2)

To run it, download managedwinapi-0.3.zip and extract the ManagedWinapi.dll to the same folder as the source code.

When you run the code, it enters Accessibility test text into New listbox item text box and clicks Add Item button. The controls are always on the same position within the Children enumeration so we can use direct referencing: e.g. guiat_acc.Children[3].Children[2] is the button accessibility object.

Enhancing this example is up to you - I have created several functions that take care about entering the text into text boxes, selecting buttons or a checking check boxes. That's all I need to create a script that installs our application.