Saturday, February 25, 2006

Wow - lots of stuff to try and remember...

I guess this little blog will get lost in the flood of PyCon blog stuff - or else everyone will be so busy at PyCon that this entry will stand out (whether that's a good thing or not I am not sure :-)

It sounds like there are one or two people actively using pywinauto - and I am getting some feedback, some bug reports, some suggestions - It's great - but I need to be organized so I don't loose it. So I am going to put some of it here...

First of all there is a Python meetup in Boston on Thursday 9th of March, and if I can get my act together (a Powerpoint presentation and a good demo I guess?) then I will be presenting pywinauto.

So here are the things I want to track
  • Some applications implement menu's as Toolbars (Internet Explorer for one) and of course MenuSelect() or MenuClick() doesn't work on those. I need to research if there is some style or setting that says a toolbar button will actually popup a menu. If there is I can update the MenuSelect/MenuClick function to use them, but if not they you will have to document to use one of the following methods:
    app.dlg.TypeKeys("%FWF") # &File->Ne&w->&Folder
    or
    # this functionality is not implemented yet - still
    # need to change the interface
    to Toolbar buttons.
    app.dlg.Toolbar.Button("File").Click()
    app.PopupMenu.MenuSelect("New->Folder")

    For now I should just update the documentation (as I feel that will be the final outcome anyway). Especially as the example given was a control with class WTL_CommandBar (which is a different kettle of fish completely!)
  • I wanted to add my reasoning for creating pywinauto to the documentation and say why I think it is better then a lot of automation tools out there (the idea at least - I hope the implementation doesn't let it down!)
  • Some way of specifying unique text when looking for a control. For example if you look for a control with the text "Click this button to save as PNG" (maybe there are other buttons "Click this button to save as XXX", etc), then it would be nice if app.dlg.PNG.Click() would work - but it doesn't :-(. The reason is that the matching algorithm I use (using difflib) takes the overall text match - and the match of PNG in the overall text is low.
    The reason that I do not just select the best match (original code did do this) is that it matches sometimes when you don't want to. For example if you want to check if a dialog exists for example you could write

    if app.dlg.Exists():

    # do something because this dialog exists

    but if the searching is not strict enough it will find other dialogs and the script will be broken (and it might be hard to fix). Currently the way around is either specify more of the text:
    app.dlg.
    ClickbuttontosaveasPNG.Click()

    or use the window_ method...
    app.dlg.window_(title_re =".*PNG$").Click()

    One idea was possibly to allow something like
    app.dlg.PNG_IN_.Click()
    or maybe
    app.dlg[".*PNG$_RE_"].Click()
    where the _IN_ and _RE_ specify that the text should be 'in' or should be tested using a regular expression. I am not sure about either of these as they appear to be a bit 'magic'.
  • Finish off the Wait* functions. Currently in application.WindowSpecification (which is the class you get if you do app.dlg, or app.dlg.ctrl) there are the following methods:
    Exists(self, timeout = exists_timeout))
    WaitReady(self, timeout = window_find_timeout, wait_interval = window_retry_interval)
    WaitNotEnabled(self, timeout = window_find_timeout, wait_interval = window_retry_interval)
    WaitNotVisible(self, timeout = window_find_timeout, wait_interval = window_retry_interval)


    These should all have the same signature, and then I need to fill out the rest of the methods ^Wait(Not)?(Enabled|Visible|Ready)$. Though just writing that and thinking of duplicated lines of code - maybe I should just have a Wait() method e.g.
    app.dlg.control.Wait(enabled = True, Visible = False)

    would return the control being waited for once it is both Enabled and Hidden (unlikely to be very useful :-) or return None on timeout (or should it raise an exception?)
  • Clear up where to look for appropriate methods. Most methods are in the control wrapper for that particular control (or it's base class(es)) but some (important) methods are in WindowManager. So to be clear the available methods for a particular window are the union of
    - methods of WindowSpecification
    - methods of the Wrapper for this control
    - methods of the base class(s) of the wrapper
  • Look into pyAA to help getting information from 'difficult' controls (and possibly other uses for it too!)
  • Then all my various ToDo items:
    - Implement 'application data' that will allow the same script to run on many languages
    - Implement basic Recording functionality
    - Lots more of everything (wrapped controls, tests, examples, documentation, etc)

Thursday, February 16, 2006

Test Infected

I haven't gotten around to reading much of the XP material (well a little online), but with pywinauto I finally started to do some unit tests. Even though my coverage is still quite minimal - I don't have even one test per method yet (and some require more then that!) - I have found that it has helped me to find numerous bugs that I hadn't known about - or wouldn't have known about until I released!

I end up running the tests or at least part of the tests frequently. I am not quite to the point where I am first creating a test for the functionality that I have yet to code.

I now understand why tests make refactoring easy - you change your code until you feel it is refrigerator ready - then you run your tests and make sure that they run like they did before you ripped out that gangrenous rotting piece of code that you smelled last week. :-)

The next thing that I need to do is to add the examples to the tests - that way I will have some 'integration' tests along with all the unit tests. :-)

I feel a release coming soon - and then I think I may need to take it easy for a little while.

Sunday, February 12, 2006

It's not only my code!

I made some progress this evening - but I seem to be doing more refactoring and catching up on unit test implementation then adding much to the code base.

I have a lot of firsts (for me) with pywinauto.
  • First project I release publicly
  • First time I have ever written a unit test (yeah I know - bad :-)
  • First time I have ever had to worry about non functional changes I make to code affecting others (Like changing the interfaces of classes)
  • First time I have used subversion or used SourceForge for hosting a project
  • First time I ever thought of blogging (and maybe you are wishing I never DID!)

I'm enjoying the experience - and I think I am learning quite a bit. Here's hoping that my code is useful and I don't waste people's time with either bugs or excessive changes.

Maybe I should think of having the subversion repository hosted somewhere public - so that other's have a chance of contributing and keeping me in line. I think for now there is lots I can do myself, and I am not sure I want to anyway. I am not sure I have enough experience to be able to do it successfully - and with amazing tools like Python and ctypes - there is a lot one person can do :-)

Friday, February 10, 2006

Packages, smackages!

I had never created a package before working on pywinauto. I just made scripts and if they required other python files that I wrote then I just stuck them in the same directory and imported them from there
import myotherscipt
Then I decided for pywinauto to try and move things around and be better organized - so I created some packages pywinauto.controls and pywinauto.tests.

What feels strange to me is that these packages are not self contained, I don't mind having to rely on class capabilities defined in other packages (e.g. when testing - that the controls passed in have a Rectangle() method) but I don't like having to import pywinauto.win32defines or other modules from pywinauto. It seems to me that packages should be more self contained then that?

Should I just do away with these packages and have everything as a flat structure? Should I re-structure so that the parts of pywinauto that I do have to import are in a package of their own (that does not need anything from pywinauto)?

Well it looks like __path__ is what I need. I guess my pywinauto.controls is not really a package - and I want a directory just for organization. I think pywinauto.tests is a package - as I need to initialize it, and I expect it to always be imported by using import tests (or import pywinauto.tests)

hmm - a little more analysis needed I guess to resolve those dependencies.

New blog - marketing for pywinauto

Never thought I would start writing a blog - but it seems to be an important marketing medium for open source projects - so I guess it can't hurt too much :-)