sugarbot's aim is to provide testing and automation facilities for the OLPC Project's Sugar GUI. The project must first identify and evaluate possible implementation options, and then implement the best choice. Although it has a Sugar focus, sugarbot should be easily extensible to other Python-based GUI's.

Tuesday, December 16, 2008

Un-kludging Code

With my new-found free time, I'm going to be going back through Sugarbot with some "fresh" eyes, and hopefully un-kludging some of the code. One top of that, here is the "short list" of To-Dos:

1.) Test execution inside sugar-jhbuild as a stand-alone activity that emulates other activities.

2.) Enable synchronous execution and GUI updating. The current model waits for the GUI to initialize and then performs all of the manipulation while the actual drawn GUI is frozen. All of the behind-the-scenes stuff still works, but you can't see progress as it's happening.

3.) Implement full-auto mode with sugar-jhbuild, so that it can be integrated into the build process.

Monday, September 1, 2008

Screencast, 0.1 Release

I've managed to finally get the screencast and 0.1 release published. You can find it in the usual place, on the sugarbot Google Code site.

This screencast showcases a lot of the automation of sugar/sugarbot, with a small demonstration of how Python is used inside of sugarbot. There is also emphasis on catching errors when they occur, and how those errors are reported/displayed.

The example scripts provide a better demonstration of how the scripting works than the video could have, so I left most of the scripting details out (it is just Python anyways, so it's not very exciting).


Monday, August 18, 2008

Finalizing...

I am trying to get the final screencast properly edited and dubbed, and will be putting the 0.01 package online soon. It has been quite the day for me, as Murphy's Law would have it, everything decided to go more then slightly haywire when I decided to record video :-\

Wednesday, August 13, 2008

Combo boxes working, wrapping up

Got the combo-boxes working the way I want them to. I realized that convenience-handling for each and every Widget type is not something that is [1] perhaps not entirely necessary and [2] certainly not entirely necessary right this instant. With that in mind, I'll be wrapping up/documenting the code for an initial 0.1 release on Friday.

I'll be working on another screencast that will demonstrate integration with buildbot, automated launching of sugarbot and Sugar, as well as the new Python scripting abilities. Overall, I'm very pleased with where I am right now.

It's been a lot of fun developing for GSoC/the Python Org/One Laptop Per Child, and I'm sad to see the summer come to an end (less free time to work on it) in the next few weeks. Hopefully I'll be able to keep my motivation up to keep development going.

Once I have the GSoC-final screencast up, I plan on publishing it to all of the mailing lists. Thanks to Grig and Titus for providing me with guidance and advice throughout the summer, you guys are really great. Also, thanks to those of you on the mailing lists and IRC channels that also provided tips, insight, and advice that made those obscure API problems so much simpler.

Zach

Monday, August 11, 2008

ComboBox'es

Working on select capability of ComboBox and similar widgets tonight. It isn't a problem in itself, but trying to keep the code as flexible and clean as possible is making it into a problem.

Tuesday, August 5, 2008

Cleaning up logging functionality

Cleaning up a bit of the logging functionality on the RPC-server side of stuff. Most of it has to do with better correlation of individual clients with given status messages. A small side-effect of this is that pinpointing errors should be easier.


Old Output:

sbRpcServer : INFO     Listening on port 54321
sbRpcServer : INFO Kill: True Restart: True
sbRpcServer : INFO Added script sbpython_script.py [Activity Calculate]
sbRpcServer : INFO Serving script sbpython_script.py to client Zach
sbRpcServer : ERROR sugarbot client disconnected prematurely.
sbRpcServer : ERROR Reason: Execution failed: Traceback (most recent call last):
File "/home/zach/Activities/sugarbot.activity/sbexecutionengine.py", line 92, in executePy
sugarbot_main(self.widgets)
File "[string]", line 7, in sugarbot_main
AssertionError


New Output:

sbRpcServer : INFO     Listening on port 54321
sbRpcServer : INFO Kill: True Restart: True
sbRpcServer : INFO Added script sbpython_script.py [Activity Calculate]
Zach : INFO Starting sbpython_script.py
Zach : INFO Success (sbpython_script.py)
Zach : INFO Disconnected [1\1\1]
Zach : INFO Starting script sbpython_script.py
Zach : ERROR Execution failed:
Traceback (most recent call last):
File "/home/zach/Activities/sugarbot.activity/sbexecutionengine.py", line 92, in executePy
sugarbot_main(self.widgets)
File "Sugarbot Script: 'sbpython_script.py'", line 7, in sugarbot_main
AssertionError

Zach : INFO Disconnected [0\1\1]

Hurricane

Supposedly there's a decent-sized tropical storm/hurricane coming through right now, but it just looks like a bunch of regular old rain. Anyways, campus is shut down today, so I get some time to work on Sugarbot.

Next Tuesday I fly back out to the [Government Agency] to take my polygraph tests again.

Monday, August 4, 2008

With the half-hour runs, everything is still running fine with Buildbot.

Update: Looks like there were about 30 half-hour runs of Buildbot that went by just fine. I don't know why it was crashing at the 6-hour mark and thereafter. Must have been something weird.

Sunday, August 3, 2008

DBUS problem time-related?

I changed the buildbot master.cfg to have the slave run every minute... so far I've got 10 runs in a row without issues. However, the last time buildbot was started (using the same SVN revision) it ran correctly the first time, then DBUS went crazy when it ran again 6 hours later.

I'll change it to 30 minutes and see how it fares overnight.

Hmm.

DBUS Flaking Out

It looks like DBUS starts flaking out after a few runs inside of buildbot. No idea what's causing the issue, as the trace doesn't involve my code at all.

ERROR:dbus.proxies:Introspect error on org.laptop.ActivityRegistry:/org/laptop/ActivityRegistry:
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include:
the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout
expired, or the network connection was broken.
DEBUG:dbus.proxies:Executing introspect queue due to error
Traceback (most recent call last):
File "/usr/share/sugar/shell/view/Shell.py", line 98, in _start_journal_idle
if registry.get_activity('org.laptop.JournalActivity'):
File "/usr/lib/python2.5/site-packages/sugar/activity/registry.py", line 114, in get_activity
info_dict = self._registry.GetActivity(service_name)
File "/var/lib/python-support/python2.5/dbus/proxies.py", line 68, in __call__
return self._proxy_method(*args, **keywords)
File "/var/lib/python-support/python2.5/dbus/proxies.py", line 140, in __call__
**keywords)
File "/var/lib/python-support/python2.5/dbus/connection.py", line 607, in call_blocking
message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include:
the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout
expired, or the network connection was broken.
ERROR:dbus.proxies:Introspect error on org.laptop.Clipboard:/org/laptop/Clipboard: dbus.exceptions.DBusException:
org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not
send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network
connection was broken.
DEBUG:dbus.proxies:Executing introspect queue due to error
ERROR:root:Error getting activities async: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible
causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the
reply timeout expired, or the network connection was broken.

Saturday, August 2, 2008

Latest Changes

When Buildbot is allowed to run for an extended period of time (read: more than a few runs), I get a pretty cryptic error message (if you have the slightest clue what this means, please do tell):
/bin/sh: /usr/share/sugar/shell/sugarbot-launcher.py: Host is down
Buildbot is now available here: http://zachriggle.is-a-geek.org:8010/

Thursday, July 31, 2008

Crunchtime

The profs are really coming down hard on us at UH, as we are soon to enter the last week. Today I was writing code/debugging for UH for about 14 hours... didn't have time for Sugarbot. Yesterday was slightly more productive, but nothing pronounced. I don't expect that this weekend/next week will allow me to put in the number of hours I'd like to, but I'll be able to make up for that in the last week or so (I fly home on the 9th).

Even though there is a "pencils down" the week after that, I don't really intend to stop developing for Sugarbot anytime in the immediate future.

(Go figure, Google's whole plan of getting people involved in the FOSS community worked.)

Monday, July 28, 2008

Trying to keep it pretty...

I'm working on the sbpython.py code, trying to implement more functionality (manipulating the title explicitly, the selected entries in a ComboBox, focus, delete/backspace). Keeping the code coherent is kind of a pain, since there isn't an obvious way to keep some of the code from being duplicated.

Hmm.

Sunday, July 27, 2008

It's Alive!!!


Sugarbot/buildbot integration is complete. I only have one port opened on the box that it's running on, but you can access it here: http://129.7.243.13:22. To access that with Firefox, you need to change a setting. I'm working on getting a different port opened.


Wednesday, July 23, 2008

Mutliple Clients, Return Status

Sugarbot's XML-RPC server should now support multiple clients. Clients are identified by either an integer or string, which is supplied by an environment variable. This way, failing clients can easily be identified. Alternatively, they can be assigned a random number for the session ID.

The sugarbot-launcher script also works the part, and grabs the completion status from the XML-RPC server and returns whatever value it should (0 if there were no failures, 1 if there were). This should allow sugarbot to be used with buildbot.

Update: The code will be on SVN shortly. Looks like Google is doing maintenance.

Tuesday, July 22, 2008

Multiple Clients

Trying to get the RPC-server set up to handle multiple clients. This will allow me to request return statuses from the RPC-server to return via the sugarbot-launcher... which in turn allows the whole sugarbot/buildbot thing to work.

Yaaay!

Sunday, July 20, 2008

Big Changes

Some extremely large changes today. The old system has been completely removed (all of the manual-parsing stuff) and replaced with the native Python stuff. I have most of the stuff for buildbot reporting in place, but have not finished it yet. I need to re-do a bunch of the nose-testing stuff tonight before I get too far along.

For comparison, here is the first demo script. Much easier to use, less error-prone, and is overall actually useful.

sugarActivityName = 'Calculate'

def sugarbot_main(widgets):
one = widgets['1']
plus = widgets['+']
enter = widgets['enter']

one.click()
plus.click()
one.click()
enter.click()

widgets['TextEntry'].text = "1+5"
assert widgets['TextEntry'].text == '1+5'
enter.click()

Inheritance

Evidently, for properties to work ... properly ... the class has to inherit from the object base class.

Saturday, July 19, 2008

Somebody please tell me why the following code does not work as one would expect (that is, printing out text when setting/getting someASDF.text):

class asdf:
def click(self):
print "click"
def getText(self):
print "getText"
def setText(self, val):
print "setText"
text = property(lambda self: self.getText(), lambda self, v: self.setText(v))

Friday, July 18, 2008

So Close!

So very, very close. Just trying to get the text-setting/getting properties to work.

For comparison purposes, here is a script that uses native Python:

one = widgets['1']
plus = widgets['+']
enter = widgets['enter']

one.click()
plus.click()
one.click()
enter.click()

textEntry = widgets['TextEntry']
textEntry.text = "1+5"
assert textEntry.text.beginswith('1')

enter.click()

Missing Something

In the process of transitioning from the custom-parsed sugarbot scripts to a much simpler system using the native Python parser. A few hiccups, but I should have things sorted out soon.

Wednesday, July 16, 2008

Sugarbot Diagram

I created a small diagram that shows most of the high-level functionality of Sugarbot today for a friend, and thought it would be beneficial to share it with all interested parties.

Tuesday, July 15, 2008

Stateful XML-RPC Server

Ironed out some bugs with the instantiation of the sugarbot activity in some corner cases. Now I'm working on the XMLRPC server implementation to be able to handle sessions. Looking for a graceful way to do it so that I can just use a mix-in with the ServerProxy class and not have to do any modification beyond that.

Essentially, I want to be able to automate do the following

someObject.setValue(foo)
someObject.someMethod(bar) === someObject.someMethod(foo,bar)

It looks like the __call__ property may be able to help me out with this.

Saturday, July 12, 2008

Full automation

When launching sugar-emulator with environment variable SUGARBOT_EMULATOR set, automatically launches Sugarbot. When the Sugarbot activity closes, it is re-launched if there are other scripts that still need to be executed. Once execution of the scripts are complete, the Sugar shell is killed (SIGTERM).

SVN revision 81 has the goods. (modded-main.py is the replacement for shell/main.py)

Automated Launching: Go!

Using just about the most obscure Python code I have ever written, I have just made sugarbot fully automatable.

It requires a small patch to main.py in the main Sugar directory (/usr/share/sugar/shell/main.py), and adding a file to the same directory. It launches sugarbot by simulating a click on the sugarbot icon in the frame.

Will put the code up on SVN later, it's Pizza time now!

Important Code:
# =========================================================
# The magnitude of this hack compares favorably with the
# current national debt.
boxChildren = self.shell.get_frame()._bottom_panel._bg.get_children()
tray = [k for k in boxChildren if isinstance(k,ActivitiesTray)]
if tray:
children = tray[0]._tray.get_children()
else:
return
activities = [k for k in children if isinstance(k, ActivityButton)]
sbList = [k for k in activities if k._activity_info.name=="sugarbot"]
# ========================================================

if len(sbList) > 0: sbList[0].emit('clicked')

main.py patch:
model = ShellModel()
shell = Shell(model)
service = ShellService(shell)

if os.environ.has_key("SUGARBOT_EMULATOR"):
from sugarbotlauncher import SugarbotLauncher
sbLauncher = SugarbotLauncher(model,shell,service)

try:
gtk.main()
except KeyboardInterrupt:
print 'Ctrl+C pressed, exiting...'

Launching Activities Automatically

Haven't found a hooking point yet, but I've gound out the API call to launch the activities.

sugar.activity.activityfactory.create(...)

Friday, July 11, 2008

Mid-Summer Screencast

The screencast is up here [mp4] and here [avi].
The SVN repo has been updated to use the same code as the screencast (r77).

Accomplishments thus far:
  • Masquerading as any Activity while retaining all functionality
  • Hooks into PyGTK library to intercept GDK Events to catalog widgets
  • Intelligent identification of widgets based on widget class to give each widget a unique identifier
  • Manipulation of many types of widgets using generic commands like 'click' and 'type'
  • Multithreaded execution routine prevents hang-ups (prior versions would stall once the calls to the GTK handler stopped due to inactivity)
  • Custom scripting language with support for advanced string manipulation [will soon be replaced by native Python code]
  • XML-RPC client/server interface allows the scripts to be stored on a central machine, while sugarbot may be run on any number of slaves.
  • Per-command status reporting and graceful error handling
  • Does not rely on any libraries or modules outside those already provided by Sugar and Python
  • Automated testing provided via buildbot and python-nose.

Have fun!
Questions, comments, and rants are welcome and appreciated.

Thursday, July 10, 2008

WTFBBQ

So the problem is absolutely, 100% NOT with my code.

Running the example Activity here does NOT produce the "Hello World" output when the button is clicked. Changing the 'log.info' statement to a 'print' statement makes it work just fine. The logging module is broken or otherwise not functioning with the latest sugar packages on Ubuntu 8.04.


ScreenFlick

With the upcoming mid-summer review, it's time to throw together a screencast and show off all that sugarbot can do. I've found a piece of software, ScreenFlick, which allows me to do just that, and to do so pretty easily. It's only for Mac OS X, and keeps the interface simple (just the way I like it). It supports some nifty features, standard stuff following the mouse, variable framerate, lossless video compression, as well as some nicer options (a visual indicator for mouse-clicks, visual indicators for keyboard activity).

Some screenshots...

The software is pretty self-explanatory, and saves the videos in .MOV format, so you can easily edit things together in Quicktime Pro. Once I'm all done, I'll probably convert the files into MP4 with VisualHub, another nice utility (which I generally use to convert videos to be iPod-compatible).

Tuesday, July 8, 2008

O ya

It's my (20th) birthday.

Wierd logging issue...

When I was doing the screencast today, I went to show that the logs were cataloging all of the identifiable Widgets... but for whatever reason, the logs were mostly empty.  I reverted to r59 (my demo version), and the logs were *still* empty.  So I deleted ~/.sugar/*... *still* no logs.  Dunno what's going on, just kind of bizarre.

Woot?

sudo xhost +

Well that was pretty friggin simple. Only a few *hours* of Googling for that one. The buildbot is not yet publicly accessible, but it now runs all 70 tests just fine. My Google-fu has truly failed me :-(. In my defense, I did find the solution earlier, but the prior finds didn't mention that the "xhost +" command had to be run as root.

Zach's to-do list:
[x] Fix issue with current buildbot
[ ] Screencast
[ ] Start sugarbot automatically
[ ] Automated testing using buildbot/scripted sugarbot

Monday, July 7, 2008

Buildbot is [almost] working

So I got buildbot up-and-running last night, and have been troubleshooting a few problems with importing some of the Sugar functionality.

Here is what I get: link (don't want to clutter the blog with a huge output). Essentially, test_sugarbot, test_sbgui, and test_widgetIdentifier are totally skipped. What is unique to these files is that the files they import from rely on Sugar (for example, importing sugar.activity.Activity or sugar.graphics). The issue is the same line in each case:

File "/usr/lib/python2.5/site-packages/sugar/graphics/style.py", line 38, in _get_screen_dpi
xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi')
AttributeError: 'NoneType' object has no attribute 'get_property'

Unfortunately, that doesn't tell me much. I can speculate that the issue is that the buildbot-user does not have an actual X display allocated, and that Sugar is choking trying to figure out the DPI of the screen. This is pretty evident when looking above the errors:

/var/lib/python-support/python2.5/gtk-2.0/gtk/__init__.py:72: GtkWarning: could not open display
warnings.warn(str(e), _gtk.Warning)

Unfortunately, my Google-fu fails me finding anything that is relevant regarding gtk-xft-dpi, and there are way too many results for "GtkWarning: could not open display".

Sunday, July 6, 2008

Buildbot Up and Running

Buildbot is up and running, although not all of the tests will run (yet they run fine when executed manually).  I believe that it has something to do with the fact that Sugar expects a display to be present, even when you just do:

from sugar.graphics import Palette

I don't have a machine that I can put the buildbot on that can be accessed remotely (yet), but I should have a shiny new Dell any day now (it was ordered ~3 weeks ago) for my work with Univ. of Houston that I can throw a buildbot on.

Thursday, July 3, 2008

Ideas???  Buildbot complains...

Following twistd.log until startup finished..
2008/07/03 20:26 CDT [-] Log opened.
2008/07/03 20:26 CDT [-] twistd 2.2.0 (/usr/bin/python 2.5.2) starting up
2008/07/03 20:26 CDT [-] reactor class: twisted.internet.selectreactor.SelectReactor
2008/07/03 20:26 CDT [-] Loading buildbot.tac...
2008/07/03 20:26 CDT [-] Loaded.
2008/07/03 20:26 CDT [-] loading configuration from /home/buildmaster/APP/master.cfg
2008/07/03 20:26 CDT [-] error while parsing config file
2008/07/03 20:26 CDT [-] error during loadConfig
2008/07/03 20:26 CDT [-] Traceback (most recent call last):
 File "/usr/lib/python2.5/site-packages/twisted/scripts/twistd.py", line 182, in startApplication
   app.startApplication(application, not config['no_save'])
 File "/usr/lib/python2.5/site-packages/twisted/application/app.py", line 298, in startApplication
   service.IService(application).startService()
 File "/usr/lib/python2.5/site-packages/twisted/application/service.py", line 196, in startService
   service.startService()
 File "/usr/lib/python2.5/site-packages/buildbot/master.py", line 407, in startService
   self.loadTheConfigFile()
--- ---
 File "/usr/lib/python2.5/site-packages/buildbot/master.py", line 462, in loadTheConfigFile
   self.loadConfig(f)
 File "/usr/lib/python2.5/site-packages/buildbot/master.py", line 480, in loadConfig
   exec f in localDict
 File "/home/buildmaster/APP/master.cfg", line 4, in
   from buildbot.process import step, factory
: cannot import name step

2008/07/03 20:26 CDT [-] The new config file is unusable, so I'll ignore it.
2008/07/03 20:26 CDT [-] I will keep using the previous config file instead.

Next Step

Looks like my next step is to automate the Sugar interface itself, so that I can automate launching of the sugarbot application. If there is a way to automatically launch a specific Activity via command-line, please let me know.

This will ultimately allow me to write example tests for the Calculate and Terminal activity, as suggested by Grig. Those will be the first real test of sugarbot.

I've also been toying with the idea of using the Python interpreter to do the bulk of the parsing work for me. It would require some restructuring, but would ultimately be the most flexible. For example, I can think of many instances where it would be very beneficial to implement complex logic into an automated GUI test. However, re-inventing the proverbial wheel (Python interpreter) seems rather non-trivial :-). [Update: Note that I don't intend to to make my own interpreter, but rather make the current code use the interpreter]

However, I still have to tackle the issue of automatically launching sugarbot in the first place.

Feels good

How well documented should tests be? It seems like they ought to be pretty self-explanatory, otherwise they are probably too complex and are prone to breakage themselves.

On another note, this is kind of nice to see...

zach@zriggle-desktop:~/Desktop/OLPC/sugarbot/trunk/sugarbot$ nosetests test*.py
......................................................................
----------------------------------------------------------------------
Ran 70 tests in 0.581s

OK


Wednesday, July 2, 2008

More difficult than it needed to be...

I don't know why I was so stuck on the idea of *actually* using the XML-RPC interface to test the functionality exposed by XML-RPC, when I can just call all of the methods directly.

Unless something in xmlrpclib or SimpleXMLRPCServer breaks (which isn't something I can do much about), you end up with the same results.  I can't believe I wasted this much time on the problem!!!

Sunday, June 29, 2008

Issues Testing XML Server

Running into some issues getting the XML Server issues to work properly.  The problems stem from the connections not wanting to persist, or not wanting to close/open fast enough, in addition to some other oddities.

Committed several new files to SVN, lots of tests for most of the other functionality.

Friday, June 27, 2008

So wait...

You mean I can make changes now, and not have to worry that much that 13,000 things just broke?

...

AND I can find bugs in the process?

zomg

I founded a bug.  While writing nose tests.

(I tried to find a fitting lolcat picture, but couldn't.)

sugar-emulator

I'm fed up with sugar-jhbuild (building xulrunner causes the compiler to *segfault*) for the time being.  I'm just going to use sugar-emulator, even though it's an older version of Sugar.  I would imagine most of the internals will still work the same, and I'll be able to get my tests written and... tested.

Thursday, June 26, 2008

Not cooperating...

Ubuntu, sugar-jhbuild, and Vmware Fusion are not cooperating.  And it's pissing me off.

First, I tried to use the old sugar-jhbuild from before the drive corruption, because I had the actual files stored on the Mac filesystem (accessed in Ubuntu via the Shared Folders featured in VMWare).  For whatever reason, that didn't work.  Okay, I can accept that.

Next, I tried to simply './sugar-jhbuild update' and './sugar-jhbuild build' on the existing installation.  I let that run overnight.  No dice.

So I started out with a fresh copy, via git.  After 'update' passed, 'build' decided that it would freeze the VM, resulting in me having to hard-reboot (because the VMWare process would not quit via Force Quit or sudo kill).

Now I am rebuilding sugar-jhbuild *again*, and it's deciding that it's going to take its dandy time.  Literally.  I've given the VM 512MB of RAM and access to both processors, and it's sitting at about 20% utilization.  In addition to that, the VM is completely unresponsive -- which is intereseting, because it is supposedly (according to Activity Monitor in OSX) -- not really doing anything.

This whole incident is becoming very frustrating.  I can't test any of the 'nose' code that I've written, because none of the Sugar libraries are available/working under Leopard, which means that anything that's Sugar-dependent (read: everything) refuses to run on Python under OSX.

In order to see if I could expedite things, I went the 'apt' route with precreated Sugar packages and emulator.  I figured I'd just run the sugar-jhbuild process in the background, and work around it until it was done building.  As I mentioend before, the VM is completely unresponsive... to the point that I'm considering just creating a new VM (yet again...).  Of course, I know that won't really solve anything, because Ubuntu runs just fine until it gets a few minutes into the sugar-jhbuild process.

I should very shortly have access to a shiny new Dell workstation (as part of my UH project) that will have Ubuntu on it.  Hopefully that will yield better results.

Monday, June 23, 2008

Documentation Effort

Documentation of the source code has been going fairly well.  I've also knocked off a few items on my todo.txt.

Tomorrow night will kick off the nose'ing of sugarbot.

Ubuntu is running

The Ubuntu VMware machine is up and running again, and sugar-jhbuild finished last night (Update: Haha, just kidding!). I've got to do some updates for 10.5.3, and the obligatory Ubuntu updates, but everything should be working now (of course, Safari is exhibiting some weird behavior but I think 10.5.3 will fix that).

Sunday, June 22, 2008

Drive Genius

Do not use it! It may decide to hose your entire filesystem, resulting in you needing do a completely fresh installation of OS X. Thank Steve Jobs for Time Machine (and WD for making 250GB of storage available in a pocket-size form factor for $120).

After my Time Machine backup finishes restoring (looks like about 45 minutes left on that), I have to re-install my Ubuntu VM, as my VM's are the only thing I didn't have Time Machine back up (because they would chew up disk space). I'm hoping to be back up and running before the night is over.

Saturday, June 21, 2008

New Wiki Pages

There are two new Wiki pages. This needed to be done eventually, so I thought I'd take a break from coding to write up some documentation. It's pretty basic, but better than no documentation at all :-).

Sugarbot Script Syntax
Running Sugarbot

Refactoring

By the way, I am also going to do some refactoring on the sbGUI class.  It has had some functionality embedded in it that it should not be responsible for, and some of the methods are kludges as a result of the recent restructuring of the "command pipeline" (dunno what else to call it).

Not going well today...

Today has been an interesting day so far (about 6 work-hours left to go today) in that there have been multiple small bugs all conspiring against me.  (Yes, I think the Python interpreter is sentient.)

I think/hope I have FINALLY gotten things sorted out.  Maybe.

Friday, June 20, 2008

Now Launching

I have re-restructured most of the code, and I can now send commands over XML-RPC as text, and everything works fine (so far).  I have to change some of the execution code, but the issues should be minor.

Thursday, June 19, 2008

Parsing Server-side

Parsing commands server-side may run into a few issues, the first of which is that returning an object over XML-RPC does not work the way that I imagined it would.  While it provides the objects' members as a dictionary, it does not provide any information about the instance of the object -- for example, whether it is an sbInitCmd object or a sbClickCmd object.

I can make a work-around for this (for example, by making the class name a member, and then passing that to another function that re-instantiates the object) but it seems like a giant kludge.

Bug Hunting

'self.currentScript' is not equivalent to 'currentScript'.

The fact that the error was being reported via the xmlrpc library only made it that much harder to realize my mistake.

Wasted time, bah.

Wednesday, June 18, 2008

Moving

I've had to do some restructuring to get the Parser to play nice with the RPC Server, and for the Commands to still work the way they should.  

Played around with the logger functionality tonight.  Very nifty.

Tuesday, June 17, 2008

That's it, really?

I took the path of least resistance, and provide the path to the script file via XML-RPC.

After an hour of struggling with it, only to finally notice that I have to restart the server script (in addition to the Sugar Activity) if I actually want my changes to propagate, I have to say... that was pretty freaking easy.

By the way, why did nobody tell me about XML-RPC and its awesomeness sooner?

Sunday, June 15, 2008

Timout problem

I tried the threading route... that didn't work so well due to Python's GIL.  What a pain.

Good news is that the problem was solved with -- drumroll -- changing an 'if' into a 'while' and adding a little bit more hackery.

XML-RPC

Ha! I may just go with my networking idea for telling Sugarbot what to do. Usage of XML-RPC had been discussed before, and it solves at least one problem, of how to get Sugarbot to execute different scripts without swapping out script files.

A separate XML-RPC server can feed it the commands.  Bingo!

Saturday, June 14, 2008

Temporary Diversion

I just realized how convoluted the current logging mechanism was.

Fixing that pronto.

Brick Wall

Just hit a brick wall today.

Turns out that I might need to create a separate thread in order to launch the commands, as the method that I am currently using is only good until things are done initializing. After that, no new gdk.Event's are issued, which means that the place that I use as a callback to launch sbCommand objects never gets called.

For an example of what I mean, check out r41 (just committed it) and run the sugarbot activity. No modification should be necessary, and it should launch the Terminal activity (which you need to have installed for this to work properly, obviously). After/during the "sleep '2'" statement, everything finishes initializing, which means there are no more Events flying around. That means that all of the 'type' commands will not execute until some event is created. To see this, launch the activity, and do not touch your mouse or keyboard for a few seconds. Then move the mouse, and the 'type' commands should execute shortly thereafter.

Ideas:
  1. Multithreading. Just have a thread that sits and does what the hooked code would otherwise do. This would allow me to separate the sbgui functionality from the execution of commands, which is a Good ThingTM.
  2. Find a way to generate some kind of empty gdk.Event after executing a sbCommand, if there are no other gdk.Event's waiting for processing.

Friday, June 13, 2008

Reorganizing, issues with a few Widgets

Well, it's been a few days since I've had a serious blog post. I was in Maryland for Tuesday afternoon through Thursday night (got back around midnight) for interviews with the [government]. I think things went well, and hope to hear back from them (although it's a "hurry up and wait" mentality, that may be up to a month).

As far as sugarbot goes, I got a bit done on Tuesday evening at the airport, but didn't have any time to work Wednesday or Thursday. I've made a few additions so that sugarbot now reads from an actual configuration file (located in the sugarbot.activity directory for now), and can load any arbitrary activity. From the activities that I've tested (Write, Terminal, and Browse), there may be some issues getting some of the more specialized Widgets to respond properly. I need to do some research into the AbiWord widget, for example. Although they are unique to their Activity, I would like to have support for the more common ones. Unfortunately as far as a simple demo goes, Calculate.activity is a poor candidate since it [1] requires modification to be able to check the input field and [2] stores the answers along with the output. So instead of:

click '1'
click '+'
click '1'
click 'enter'
text 'calculateAnswerField'=='2'

the required script might instead read:

text 'calculateAnswerField=='1+1\n\t2' [or however a gtk.TextBuffer stores the text internally]

I have also moved some functionality around, but it is mostly just a matter of what is initialized where. For example, the sugarbot Activity instance class needed access to the parser, which means that the parsed commands had to be passed down to the sbgui object, etc. I also spent a little bit of time on the IRC channel (#pygtk) and found out a more convenient/likely to work with other kinds of widgets method for simulating clicks and typing (via Signals). Nifty.

Currently, I do not have any ideas on how to tell sugarbot which file to read from, aside from some hard-coded value. I would greatly prefer to not use the GUI to do this, so that it would be easier to automate. A few things off the top of my head that might work...
  • A script file that actually contains multiple scripts. With each subsequent execution, the next 'script' is run. sugarbot keeps track of where it needs to read from next with some other file, and resets that data once it reaches the end.
  • Use the network to connect to some separate 'server' application that tells sugarbot what to do. This other application would have unlimited flexibility, since it is not bounded by the Sugar environment.
As far as automating the process of starting sugarbot in the first place, that's another problem to tackle. I need to find some way to hook into the PyGTK calls of the Sugar process, in a similar manner that I've used to automate activities. Again, I'd prefer to find a way to do this without modifying any code in the Sugarbot base.

Wednesday, June 11, 2008

In Maryland

In Maryland right now. Got done with my polygraph and first operational interview today. Psych battery, psych eval, second op. interview, and HR interview tomorrow.

Added some parser functionality, and moved some functionality around in regards to the commands and parser while I was at the airport/on the plane. More updates on Friday.

Sunday, June 8, 2008

Multiple-Initialization

A commenter (Michael Stone) asked for a bit more information on the multiple-initialization issues that I ran into. The issue first appeared when I first started the project, and I resolved the issue with a runtime inheritance hack. The general idea is:

The sugarbot object makes itself inherit from the other class, then calls __init__(self, self.handle) so that the Activity gets initialized the way that it normally would. This was not how it was originally set up (because it did not work the way it was originally set up). At first, I just assumed that I could do the following:
self.parentClass = someOtherActivityClass
sugarbot.bases = (self.parentClass,)
self.parentClass.init(self,self.handle)
…and have everything work. Unfortunately, certain calls (calling activity.Activity.__init__ explicitly, to initialize the activity being one of those) only like to be called by the Activity instance that it expects the call to come from. Otherwise, the excrement comes into contact with the rotary cooling device.
launchedActivity = someOtherActivity(self,handle)
An issue that I’m facing is that, with the current way of instantiating Activities, it is not possible (to my knowledge) to terminate the spawned activity without causing the whole process to terminate. I think the way to resolve this is going to (ultimately) be to automate the Sugar GUI itself, so that I can re-launch the sugarbot Activity after it terminates. It will somehow know (or perhaps have this information provided to it) to run the next automation script or the like.

Example Activity:
from sugar.activity import activity
import sys, os
import gtk
class exampleActivity(activity.Activity):
def init(self, handle):
# With or without the following call, everything freaks out.
activity.Activity.init(self,handle)
# Add the path to the activity
sys.path.append(pathToCalculateActivity)
# Import and instantiate the activity
from calculate import Calculate
launchedActivity = Calculate(self,handle)

Saturday, June 7, 2008

Re-factoring mood?

Moved a bunch of classes to their own individual files.  Nothing too exciting.

Debating what my next-step is:
1.) Go through each object type and make sure the various commands work (e.g. "click algebra-ln" when the "algebra-ln" button is not exposed).
2.) Finish the parser so that it can read from command.
3.) Build a GUI so that you can select various activities (this is probably a no-no, as it messes with the GUI state, and Sugar seems pretty finicky about certain things if they get set-up twice -- which screws up spawning other activities).   Also have considered implementing this functionality in the parser (e.g.  a command with the syntax "activity Calculate").  However, that has implications of its own, since actions are only called after some Gtk events are thrown around... which only happens after the Activity has been started.  You get the idea (chicken-egg).

Widget Identifier Refactor

The widget identification code was getting to be a bit messy... and was in a place that it really didn't fit.  All of that code has been refactored into a seperate class (and subclasses).  The code is much cleaner now.  Ideally, widget identification would be simple if the set_name() method was called on each and every widget --- but that's a bit much to expect.  

That aside, sugarbot can now identify every individual widget in Calculate.activity.  Unfortunately, there are multiple ways of naming some of the widgets.  For example, Calculate.activity's toolbars.py is responsible for drawing all of the toolbar widgets.  However, some of these have (potentially) multiple names.  In the below example, there are five identifiers that could potentially be used (the five strings used).  Currently, the first one is used, but only because I have not found a way to get at the second one.  It is probably better that the second one is not used, as internationalized text could cause issues with widget identification (the "_()" operator is used in lieu of gettext()).

toolbars.py excerpt:
        self.insert(IconToolButton('algebra-square', _('Square'),
            lambda x: calc.button_pressed(calc.TYPE_OP_POST, '^2'),
            lambda x: calc.button_pressed(calc.TYPE_TEXT, 'help(square)'),
            alt_html='x2'), -1)

Log excerpt showing identified widgets:
Tracking widget id 146431428 by identifier sugarbot Activity
Tracking widget id 146431748 by identifier sugar+graphics+toolcombobox+ToolComboBox
Tracking widget id 146431908 by identifier Keep
Tracking widget id 146474524 by identifier Stop
Tracking widget id 146475644 by identifier edit-copy
Tracking widget id 146476964 by identifier edit-paste
Tracking widget id 146482316 by identifier edit-cut
Tracking widget id 146483516 by identifier x2
Tracking widget id 146483636 by identifier √x
Tracking widget id 146484876 by identifier x-1
Tracking widget id 146484916 by identifier ex
Tracking widget id 147261556 by identifier xy
Tracking widget id 147262876 by identifier algebra-ln
Tracking widget id 147262916 by identifier algebra-fac
Tracking widget id 147272364 by identifier trigonometry-sin
Tracking widget id 147273604 by identifier trigonometry-cos
Tracking widget id 147274964 by identifier trigonometry-tan
Tracking widget id 147285612 by identifier trigonometry-asin
Tracking widget id 147286892 by identifier trigonometry-acos
Tracking widget id 147286852 by identifier trigonometry-atan
Tracking widget id 147297620 by identifier trigonometry-sinh
Tracking widget id 147298900 by identifier trigonometry-cosh
Tracking widget id 147300220 by identifier trigonometry-tanh
Tracking widget id 147300180 by identifier boolean-and
Tracking widget id 147310948 by identifier boolean-or
Tracking widget id 147312228 by identifier boolean-eq
Tracking widget id 147312268 by identifier boolean-neq
Tracking widget id 147322876 by identifier π
Tracking widget id 147324116 by identifier constants-e
Tracking widget id 147330788 by identifier Deg
Tracking widget id 147337740 by identifier enter
Tracking widget id 147337660 by identifier )
Tracking widget id 147337580 by identifier /
Tracking widget id 147337500 by identifier *
Tracking widget id 147337420 by identifier (
Tracking widget id 147332148 by identifier -
Tracking widget id 147332228 by identifier +
Tracking widget id 147333028 by identifier clear
Tracking widget id 147332948 by identifier .
Tracking widget id 147332868 by identifier 0
Tracking widget id 147332788 by identifier 3
Tracking widget id 147332708 by identifier 2
Tracking widget id 147332628 by identifier 1
Tracking widget id 147332548 by identifier 6
Tracking widget id 147332468 by identifier 5
Tracking widget id 147332388 by identifier 4
Tracking widget id 147332308 by identifier 9
Tracking widget id 147331988 by identifier 8
Tracking widget id 147332188 by identifier 7
Tracking widget id 147331828 by identifier calcMainEntry
Tracking widget id 147332028 by identifier Label
Tracking widget id 147337820 by identifier All equations
Tracking widget id 147337900 by identifier Show history
Tracking widget id 139099748 by identifier SugarActivity

Thursday, June 5, 2008

Getting pretty sugar-specific

I'm getting into some of the nitty-gritty with Sugar here, trying to handle some of the Widget types that it defines itself.  Kind of a pain, but alas...

Wednesday, June 4, 2008

Bandwidth

Bahahahaha.



Unfortunately, this is only in the computer lab in one of the buildings. In the dorm rooms, they regulate it to 384/128 kbps.

Tuesday, June 3, 2008

Damnit, Python

Just spent two hours trying to figure out why some code wouldn't do what I wanted to.

class sbTypeCmd(sbCommand):
"""
Types text into an Entry widget or similar widget with a set_text method.
"""
def __init__(self, sbgui, widgetName, params=None):
sbCommand.__init__(self, sbgui, widgetName, params)

def run(self):
print "sbTypeCmd"
widget = self.getWidget()
methodName = "set_text"
if hasattr(widget, methodName):
print "Hasattr"
text = (" ".join(self._params)).split("'")
print "Text: " + text
if len(text) <>
return False
textToType = "'".join(text[1:-2])
getattr(widget, methodName)(textToType)
return True
return False

Flipping indentation.

Monday, June 2, 2008

Evaluating Entries, basic parsing

Basic strings such as:

click '1'
click '+'
click '1'
click 'enter'

and complex strings such as

entryEval 'Entry'.split()[0] == '1'

Are both parse-able AND should work the way that they're expected.  Pretty cool.  Source is on SVN.  [edit] I have also quickly implemented a feature that will allow the serialization of sbCommand objects -- so that not only can lines like the above be parsed, they can be un-parsed.

Note: In order for Entry hooking to work properly, the gtk.Entry has to [editbe named properly.  For testing purposes, I named Calculate.activity's main entry "Entry".  I will include a patch to automate this process at a later point in time. [edit] Manual patch below, will upload a Diff to the sugarbot downloads area.

Underneath the line in Calculate.activity/layout.py:
  self.text_entry = gtk.Entry()
Enter the following (my personal tests use:
  self.text_entry.set_name('calcMainEntry')

Houston

In Houston right now, everything is going well so far.  I got a bit of sugarbot coding done last night on the plane, and in the Airport lobby.  Trying to come up with a framework that will allow flexibility in the commands, and I think I've got it.

Will have updates later.

Thursday, May 29, 2008

Automation, GO!

Got some button-press automation going.  It's a pretty simple implementation, actually.  Currently, it only handles one action ('click') and one Widget type (gtk.Button), but expanding it should be straightforward.  I ran into a problem where the user-defined action would attempt to execute before the corresponding Widget was instantiated, so I added a mechanism that will delay for 10 seconds (in .01 second increments) before giving up on an action.

The code is also on SVN now.

self._commands = [sugarbotCmd(self,'1','click'),
sugarbotCmd(self,'+','click'),
sugarbotCmd(self,'1','click'),
sugarbotCmd(self,'enter','click')]

Simple Button Click

I have found a suitable place to inject commands (via use of gdk.event_peek()), and have successfully tested injecting commands (button-clicks) based on a Widget identifier (in this case, a button label).  Going to refactor the code so that it's more generic, and so that multiple actions can be queued.

Wednesday, May 28, 2008

Health Testing

Once again, not related to sugarbot, but pertinent nonetheless: 
Went in for a preliminary test today, looks like diabetes.  Turns out that I am glycosuric (glycosuria), as the test came back at over 2000 mg/dL glucose, and it should be between 160-180.  Going tomorrow morning for blood work, and a follow-up on Friday.

Monday, May 26, 2008

Being too cautious

I've been dissecting the various layers of the Calculate.activity for the past few hours, trying to find out how little bits of it work, and how to be able to identify different parts of it by label/name/title/whatever, and being able to run a Widget through a method and have it hand me back a useful name (e.g. "9" for a button labelled "9").  However, this is proving to be difficult for some of the non-elementary types (for example, Widgets inside the tabs of a Gtk.Journal; and Gtk.Alignment containers).

Being that I think I spent more time than is necessary at this point, I'm shifting just dealing with buttons for the time being.  By just working with buttons, I can ignore a lot of the crap flying around inside GTK, and lay a framework for extended functionality.  I just feel the need to get something up-and-running that is automated.  I keep getting sidetracked by attempting to implement more than is necessary right now (like handling Gtk.Journal's).  Need to stay focused.

Scheduling Bloodwork

Just thought that it was noteworthy, I am going to schedule an appointment tomorrow to get some blood work done, and get tested for diabetes.  I've been having most of the symptoms of Type I for about a week now (dry mouth, extreme thirst, excessive bathroom time, blurry vision, and lethargy) and have a family history of diabetes (paternal grandfather, two of my three cousins on my dad's side of the family), so it's pretty likely.  I've been holding off to see if some of the symptoms will go away, but it doesn't seem like they want to.  Most places are closed today, so I'll be making an appointment tomorrow, will probably be going on Wednesday (also getting dental work done on Wednesday)... so this is an interesting week.

Aside from the aforementioned complications, it looks like the University of Houston might be sticking me on a project that I have no interest in --- which will subsequently require me to not visit Texas this summer.

Wednesday, May 21, 2008

Enumerating Widgets

I'll just say that there are way more types of Widgets in use than I originally anticipated... and the hasattr() and isinstance() functions are godsends.

Note: This post is actually being written at 1:30AM on Thursday, but I didn't want it to look like I didn't do anything on Wednesday the 21st.  This post includes information about work done on the 21st as well.

Tuesday, May 20, 2008

WOOOOOO

So... modifying inheritance at runtime is about the coolest thing EVER.  I have succeeded in getting Calculator.activity to run inside of my own activity, sugarbot.activity.

...mostly because it made my code work.  :-).  Most of what I've toyed around with the past two or so days is useless, so I'm stripping that code out.  Some other code doesn't quite mesh with the new stuff, but I'll get on that ASAP. [Code is now on SVN nder trunk/sugarbot]

To list my accomplishments today:
  1. Figured out how to get another Activity's code running under my activity, via runtime inheritance.
  2. Successfully identified button-presses in Calculator.activity.  Example output:
Window sugarbot Activity created
Button pressed: 3
Button pressed: +
Button pressed: 3
Button pressed: enter
Button pressed: 5
Button pressed: -
Button pressed: 5
Button pressed: enter
Button pressed: None

Altogether, today was a pretty good day.  The example output above shows that there are definitely going to be some stumbling blocks with some portions of some Activities, as not all of the Widgets are named properly (the last 'None' press was the stop-sign icon to stop the Activity).

    Monday, May 19, 2008

    Which came first, the snake or the egg?

    I've run into quite an interesting little debacle.  The only function that I can guarantee gets called when an activity is loaded is myActivity.__init__().  Unfortunately, if I create an instance of a different activity, its anotherActivity.__init__ function is called.  For whatever reason, Sugar wants to attach a few things to myActivity object.  However, myActivity.__init__ has not finished execution, so a TypeError exception is raise.

    Maybe spawning a separate thread would solve the issue?

    Update: Solved the issue by using runtime inheritance, by some nifty manipulation using __import__ and __bases__.

    Migrating to an Activity

    As was suggested in the IRC channel last night, I'm going to create a small OLPC Activity wrapper for the time being.  All that the code will do is launch Calculate.activity inside itself (so technically not 'launching', but actually reading activity.info and calling the appropriate functions).  From there, I'll be able to check and see if I can intercept PyGTK messages.  I am assuming that I'll be able to, so that will be a great first step at actually working inside Sugar.

    As far as this method goes, it removes the possibility of actually automating the Sugar GUI itself (but the functionality could be designed-in later), as far as the frame, ring, and Activity list go.  I doubt that these are aspects that will need in-depth testing, as their function is severely limited.  However, being severely limited in function, it should be easy to extend sugarbot to automate those features as well.

    Hoping to have a copy that snoops on Calculate.activity and (potentially) automates a few basic operations done tonight/early tomorrow.  Will upload everything to SVN when that is done.

    Sunday, May 18, 2008

    What is our scope?

    In #olpc on Freenode, an individual by the name of 'homunq' suggested that the automation tool be rolled into its own Activity.  It could then be used to launch other Activities in its own process.  That would solve the problem of everything being in a separate process.   This would have to be done in a specific manner, since BitFrost prevents Activities from launching one-another, but does not prevent them from calling on one-another.  It would require some dynamic import's and class calling.

    Transcript for my own personal reference, and yours if you'd like: link (mediafire.com).

    Saturday, May 17, 2008

    Roadblocks

    So I've figured out how to intercept gtk.Event's, and then match them to various gtk.Window's or gtk.Widget's.  Easy peasy.  What I would like to be able to do, is given a gtk.Window, query it for its child widgets.  Unfortunately, that approach doesn't seem like it would be a good idea, given the big variety of ways to pack widgets into a window.  I might have to come up with a case for each and every type of widget-packing class.  Not cool.

    What I think will work better is intercepting the gdk.MAP Events, and trying to relate a given Widget to its parent Window at that point in time.  I don't know how well this will work if there are pop-up dialogs or tool windows, or things like that.  I also don't know how well that will work with the Sugar interface, given that everything is effectively a big window.

    What I think would be a good way to see how the Events get thrown around when running Sugar.  I think that with the class I've got, I can turn a few things off so that it just prints out all of the Events that are generated.  From there, I can find out which ones I care about, and which ones I don't.  That should give me a good idea of the kind of functionality that will be needed (hopefully).  That's all assuming that Sugar uses PyGTK (which I am 99% sure it does), and that when it launches activities, it keeps them running in the same process (which I am about 50% sure it does).  I'll know later tonight, I guess.

    Workin' It Out

    Still having some issues figuring out how a few things work in kiwi.ui.test's common.py.  I think most of the confusion stems from the fact that some of the functionality implemented in common.py directly interferes with what I'm trying to do, and it takes me a while to catch on.

    On a side note, it appears that I might run into some issues with gtk.Entry naming.  Being that Entries do not have any built-in labeling mechanism, the chances that developers are naming the entries properly are slim, I think.  I might have to create a mechanism to create names for entry-boxes.  This runs into the issue of how to reliably name the entries, such that they will receive the same name each time the program is run.  I think it might be better to require developers to give them a meaningful name (or perhaps I can go into the code and do that).

    Also, got my Google 'gift' today.  It's actually a pretty nice book, titled "Beautiful Code" (and O'Reilly book).  Most of the examples are in C\PHP\Java syntax, with what might be Perl scattered here or there.  There is a chapter (Chapter 18: Python's Dictionary Implementation: Being All Things to All People) that is Python-centric, so I might find some useful stuff there.  Unfortunately, that chapter is under ten pages long.  Still, I do the vast majority of my work in C\C++, so this may come in handy :-).

    Friday, May 16, 2008

    It's hard to overstate my satisfaction

    Small achievement, but it feels nice none-the-less.  Managed to subclass kiwi.ui.test.common.py's WidgetIntrospecter successfully*, and use it to detect button presses.  I should be able to use the same method to invert the processs -- to simulate button presses.\

    Whoops.  Understate != Overstate

    *Which means that I was correct about my earlier deductions regarding what the code segments do.  Will post the code shortly.

    More kiwi.ui.test

    I've been looking through kiwi.ui.test since I woke up this morning, and I think I have a reasonable grasp on what a lot of the code does.  A kiwi.ui.test class, WidgetIntrospecter, seems to perform the bulk of the functionality that I'm interested in.  It looks like it's able to function like it does, because it [1] inherits from gobject.GObject, and [2] calls event_handler_set() on one of its methods.  That method then gets to see all of the events that fly around inside of GDK, and then it hands that event off to gtk.main_do_event().  According to the API documentation, that function allows you to force GTK to act on a single event.

    The kiwi-specific code seems to be extremely minimal (in WidgetIntrospecter, anyways), so I'm going to play around with the class for a bit, and see if I can get it to run without any 'import kiwi' calls.

    *If anybody would care to explain when it is proper to use GDK versus GTK, it would be greatly appreciated.  I'd prefer to not look like an idiot when talking to someone more savvy :-). 

    Thursday, May 15, 2008

    kiwi.ui.test

    I was looking for a bit of advice regarding PyGTK in general, so I hopped on the IRC channel today.  I asked a few pretty general questions, and ended up talking to the guy who wrote kiwi.ui.test.  I talked a little bit about the implementation, and we agreed that our goals are "very much aligned".  Cool stuff :-) (Grig had mentioned kiwi in an email, but I couldn't find any relevant material -- I guess I just didn't look hard enough)

    As far as actual development goes, I didn't do much today.  I spent a while poring through PyGTK API documentation, kiwi source, and guitest source.  Still haven't heard back from the guitest writer.  The only other response I got from the IRC channel seemed to think that GUI automation from a separate process, without relying on accessibility information, wasn't quite sane.

    I've pretty much abandoned both ecto and MarsEdit.  ecto wants to force arbitrary compliance on HTML, and MarsEdit provides no WYSIWYG.  Unfortunately, the Blogger WYSIWYG editor doesn't seem to like copy-and-pasting text, without using the right-click-paste method of pasting.

    My sleep cycle has been off for the past week (sleep 3AM-Noon), which interferes with my ability to get work done and not be disturbed by my significant other.  I'm getting to sleep early tonight (sometime before midnight) so that I can get up at a reasonable time tomorrow (perhaps 8-9AM).  This should give me significantly increased productivity :-).

    Dissecting guitest

    So, dogtail is huge. Really, really huge. So huge, in fact, that I'm a little bit opposed to trying to wrap my mind around it, especially since it has a bit of a documentation problem.  As such, I'm going to stick with playing around with guitest until I get a response from the GUITAR guys.

    Back to guitest, it would appear that a vast amount of functionality stems from this little nugget. It looks like the way guitest works is by hooking pretty much any GTK call you could ever want to make.

    self._original is simply a list of 3-tuples, which are [1] itself, [2] the path, gtk.Button, and [3] the original class, e.g. Button for gtk.Button. I don't understand why it's necessary to store it's own class name... hmm.

    By the way, if anyone knows of a way for me to copy code out of TextMate that retains the syntax coloring, please let me know (extra kudos if I get it in HTML format).

    GUITAR will have to wait

    From: strecker@umd.edu
    Subject: Re: GUITAR Source Code
    To: Zach Riggle

    Zach, 

    Thanks for your interest in GUITAR. Currently, the University of Maryland's IP policy is changing, and we're still waiting to find out under what conditions we can provide the source code. I don't know when we'll find out, but I'll try to remember to notify you when we do. I encourage you to keep checking the project page periodically for updates. Sorry for the inconvenience. 

    Jaymie

    Underwhelmed

    After spending a little bit with guitest, I have to say that I am a little bit... underwhelmed at how it's implemented. Being that I haven't really used software that does GUI automation, I wasn't sure what to expect... but given the test examples that were included (along with the complete lack of documentation), I have higher hopes for dogtail and GUITAR.

    I will have to take a close look at dogtail's procedural API. It looks like it resembles what I (and I think Titus, as well) have in mind for controlling sugarbot.

    > Update: Looks like I spoke too soon. While their procedural API looks like something I'd like to look at a bit more closely, their documentation is sorely lacking.

    > Update 2: eMailed the creator of guitest. I didn't realize that it was 3 years out since it was actively maintained... but hopefully I'll get a response. It appears that he keeps an updated blog (gintasm.blogspot.com), so I'm fairly confident I will.

    > Really Not Related: Mail.app's Mailbox>Rebuild command is amazing, if not entirely apparent. I had some duplicated emails that refused to be deleted.

    Blog Archive