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.

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.

    Wednesday, May 14, 2008

    Working calculator.py

    Just finished up 'calculator.py', which is available on the downloads page. Took me a total of about 1 or 2 working hours, most of which was spent looking up API calls for GTK, and figuring out a little bit of calculator logic (particularly, how to handle repeated presses to '=' gracefully).

    (Please understand that calculator.py is messy, and this is my first attempt at a Python app that wasn't copied-and-pasted or 20 lines long, and my first real GTK app. Kudos to pygtk.org for having a decent tutorial section.)

    Setting it up to work with peekaboo is trivial, and consists of adding a few lines in main(). I might do that, but leave it commented out if somebody wants to play with it for a few seconds, and doesn't have figleaf installed, and peekaboo handy.

    Step two is going to be to automate a few keypresses using guitest. I might play around with dogtail as well, although it's been pretty well established that the method used by dogtail would prove hard to adapt to Sugar, due to its reliance on accessibility information. I still want to take a peek, perhaps to see how they structured the API? Might be worth it. Still no info from the GUITAR guys at SF.net.

    Ecto insists on screwing with my paragraph spacing. FFS

    Tuesday, May 13, 2008

    Playing with peekaboo

    Was playing around with basic PyGTK and peekaboo today. Nifty little utility, but I can't get it to auto-refresh for the life of me. Dunno what's up with that. The fact that you can do what (I assume) figleaf/peekaboo does is amazing. Makes me want to take it apart to see how it works. But I've got other stuff to do in the meantime.

    Being that I've devoured enough of Dive Into Python (the first 60 pages or so?), I think I'm going to take up a prior recommendation and try to get a concoction of a self-made calculator app and peekaboo running tomorrow. I wish that gtk.Widget was documented properly. All of gtk.Widget's function.__doc__ strings are the same crud. All that potential, and it doesn't get used. Oh well.

    Contacts and Krstić

    On a note completely unrelated to sugarbot, I got my contacts today. Not sure whether I like them better than my glasses or not. I suppose now I can't look like an idiot with glasses slid halfway down my face.

    Grig sent me a link to a blog/notebook entry by Ivan Krstić, which talks in a no-bullshit manner about OLPC XO laptops' potential use of Windows as an available operating system. I share his view on the topic, which is, paraphrased: "BFD. The OS is not important. What's important is kids learning."

    On a side note, I find it interesting that there is another individual that shares my interest in "breaking computers" that also enjoys "making computers harder to break even more" that also likes road biking. I should like to meet Ivan sometime, perhaps go for a ride.

    Monday, May 12, 2008

    How to Install VMware Tools on Ubuntu Hardy 8.04 under VMware Fusion

    Well, after spending far too much time trying to figure this all out, here is the cure: peterc.org

    And on another note, I've got SVN working with TextMate.

    All this reading has made me realize how badly I need my glasses. I'm soooo glad I'm getting contacts tomorrow. And the "Mapping Lists" feature of Python is voodoo magic. Why does this not exist in C++? (And how did I go for so long without it?

    >>> li = [1, 9, 8, 4]
    >>> [elem*2 for elem in li]
    [2, 18, 16, 8]
    >>> li
    [1, 9, 8, 4]
    >>> li = [elem*2 for elem in li]
    >>> li
    [2, 18, 16, 8]
    !!!!!!

    So I've got
    li = [elem*2 for elem in li]
    versus

    for(int i=0; i< li.size(); i++) li[i]*=2;

    Sunday, May 11, 2008

    First Post

    This is where you'll get all your news regarding the Google Summer of Code project, sugarbot.
    For more information in the meantime, check here: http://code.google.com/p/sugarbot/