Showing posts with label bughugger. Show all posts
Showing posts with label bughugger. Show all posts

Monday, March 15, 2010

Beyond Release Blockers (also a bit on bughugger and f-spot)

Release Blockers and Beyond
Every release the various ubuntu teams focus on "release blocker bugs". These are bugs that are "High" or "Critical" in importance, and are targeted to the release. Of course they also have to be assigned so that someone knows about them and can work on them.

Of course, every release the desktop team fixes lots of bugs that are not release blockers. seb128 is leading an effort to organize the team to focus on the "right" set of these non-release blockers to fix. These are personal goals that the desktop team members sets for itself.

Process
seb128 is combing through bugs that he considers addressable, and assigning the ones that he thinks will be most valuable to users if fixed to canonical-desktop-team. He sets the importants and targets to Lucid as well. pitti will then assign to specific engineers as needed. Of course, anyone is free to fix these bugs.

Bughugger
I am using bugger to watch this project. The version of bughugger that is currently packaged in universe calculates gravity and looks for attached patches. Unfortunately this makes the queries take so long, that it is basically impossible to use. (I've fixed this in my local copy, but haven't pushed the changes yet. By "fix" I mean removed the slow features.)

However, the JSON searches are working very well. From the bughugger search menu, choose JSON Searches, and you'll get a list of searches that run on a cron job on bdmurray's server.

After the results load, I can look for bugs assigned to the Canonical Desktop Team.

Because we worked in three iterations for Lucid, and minimized work for the third iteration, I am hopeful that we have a bit more time for bug fixing this cycle. However, even if the amount of bug fixing stays the same, I expect that having seb128 on point for choosing the highest impact bugs organized in a single list will help the best set of bugs get fixed by the desktop team, enhancing the general community quality efforts.

F-Spot
On a side note, RAOF has recently joined the desktop team as a Canonical supported employee! One of his first tasks was to implement the f-spot features required for the default application selection blueprint. F-spot now handles in situ editing of files. Which means no need to load images into the library to edit them, and no need to load up the gimp just do a quick crop! I cropped these screen captures using f-spot and it worked swimmingly. Thanks RAOF!



Friday, January 8, 2010

More Bug Reporting Tools


My new hero is Brian Murray. I start most mornings taking a look at our team assigned bugs. Typically running the report on demand meant waiting a good 5-10 minutes to get all the bug tasks.

So Brian copied Bryce's JSON format to make a recurring report that is compatible with Bughugger. As a result I instantly get a view appropriate for a manager. Brian is setting the script to run once per day, so it will be a tad out of date, but useful none the less, especially as I can always run the report on demand if needed right from Bughugger.

Also note the "gravity" column.

You can also just play with the JSON if you want.

Saturday, December 26, 2009

Quidgets DictionaryGrid Real Life Use Case

Bughugger is designed to make it easier for teams to manage Ubuntu related bugs by creating an extensible and fast desktop client for managing large lists of bugs.

Recall that I started working on Quidgets out of my annoyances with PyGtk programming for the Bughugger project. Specifically, the code required for the grid of bugs was extensive, repetitive, and hard to modify. I decided that I would never right TreeView code again, well, at least not directly.

This means that Bughugger is the ideal use case for me to understand the quidgets.widgets API. Here is the code that creates the above grid:

  def __setup_grid(self, bug_tasks):
"""set_up_treeview: sets up the treeview for the BugPan.

arguments:
bug_tasks -- a dictionary to set up for the Pane
"""
sw_filter = BlankFilterCombo()
sw_filter.append("=",lambda x,y: convert_to_num(x) == float(y) )
sw_filter.append("<",lambda x,y: convert_to_num(x) < float(y) )
sw_filter.append(">",lambda x,y: convert_to_num(x) > float(y) )
sw_filter.append("<=",lambda x,y: convert_to_num(x) <= float(y) )
sw_filter.append(">=",lambda x,y: convert_to_num(x) >= float(y) )
sw_filter2 = BlankFilterCombo()
sw_filter2.append("=",lambda x,y: convert_to_num(x) == float(y) )
sw_filter2.append("<",lambda x,y: convert_to_num(x) < float(y) )
sw_filter2.append(">",lambda x,y: convert_to_num(x) > float(y) )
sw_filter2.append("<=",lambda x,y: convert_to_num(x) <= float(y) )
sw_filter2.append(">=",lambda x,y: convert_to_num(x) >= float(y) )
filter_hints = {"status":sw_filter,"importance":sw_filter2}
type_hints = {"gravity":IntegerColumn,"effected users":IntegerColumn}
if self.keys is not None:
self.grid = DictionaryGrid(bug_tasks,self.keys,type_hints)
else:
self.grid = DictionaryGrid(bug_tasks,[],type_hints)
grid_filt = GridFilter(self.grid,filter_hints)
grid_filt.show()
self.grid.show()
#add the gridview to the top of the pane
self.pack_start(grid_filt, False)
#wire the treeview to the signal handlers
self.grid.connect("row-activated",self.__row_clicked)
self.grid.connect("button_press_event", self.__treeview_clicked)
self.grid.connect("cursor_changed", self.selection_changed)
self.grid.connect("move-cursor", self.__cursor_moved)
self.grid.connect("select-all", self.selection_all)
self.grid.connect("select-cursor-row", self.selection_changed)
self.grid.connect("unselect-all", self.selection_none)
self.grid.connect("toggle-cursor-row", self.selection_changed)
#create a scrolled window for the treeview
grid_scroller = gtk.ScrolledWindow()
grid_scroller.add_with_viewport(self.grid)
grid_scroller.show()
#add the scrolled window to the bottom of the pane
self.pack_start(grid_scroller, True, True)
If this looks like a lot of code, believe me, it's not. The code required to create a TreeView with the related sorting, filtering, and different types of columns would be probably 1o times the number of lines here, and would by much harder to change.

None the less, looking at the code, there are a few things that I don't like about the API at the moment:
  1. You have to connect to the myriad events related to cursor and selection changes in the DictionaryGrid. I should probably create a single "selection_changed" event, that should capture about half of the events above.
  2. Filter hints are instances of FilterCombo objects, but type hints are types. This is inconsistent and confusing. I should probably make type hints work like filter hints.
  3. You still have to manually place the menu based on the button press event. I should probably create a right click menu property on the grid that you can simply add to the grid. I could also potentially create a set of default right click functions, like "copy", and then have some simple methods to append new commands to it.
  4. There aren't enough conventions for setting types for columns. I should be able to use naming instead of the type hints. Perhaps I shall add "ends with 'count'" as a convention, and then can change "effected users" to "effected users count", and maybe something similar that would grab gravity as well, like "gravity total". Key naming seems more easy and fun than providing type hints and would reduce the number of objects required to customize the grid.
  5. Custom filters use the types stored for displaying in the grid rather than the backing values in the dictionaries. For instance, if you were making a custom filter for a CheckedColumn, rather than receiving a True or False, you would receive, a -1,0, or 1. This seems confusing to me and requires familiarity with the implementation details of DictionaryGrid. Perhaps I will replace the display values with the real values, or perhaps I may provide the display values along with the stored values.
  6. There are a few quidgets.prompts that I would like to add as well, but that's separate from the DictionaryGrid and related functionality. I'm thinking prompts.alert, prompts.info, and prompts.task. Stay tuned.
In any case, the functionality is complete enough for bughugger, so I'm pushing this code, and will get Quidgets into Universe when I get back from vacation. Then we can get Bughugger into Universe as well.

About Quidgets
Quickly + Widgets = Quidgets
There is a Launchpad Project for Quidgets
The most up to date changes are in the Quidgets Trunk Branch
You can install Quidgets from the my PPA

Thursday, December 17, 2009

Quidgets in Action: Custom Filters

I started the Quidgets project out of my frustrations with PyGtk while I was working on this bughugger tool, which a few of us in Ubuntu have been working on to help us streamline our bug triaging on the Ubuntu Desktop a bit.

We use a DictionaryGrid to display, sort, and filter bug data. In order to support correct sorting of status and importance, Brian Murray came up with a numbering scheme. However, what does status of "2" mean? We needed some text in there to also tell us what the numbers meant. But you can see the problem. Since the status and importance columns have to be typed to strings to support the extra text, the GridFilter's filter for numbers couldn't be used, but the GridFilter's string filter doesn't support < (less than), = (equals), > (greater than), etc..., which would obviously be useful.

Fortunately, GridFilter takes an optional argument in the constructor called "filter_hints" so you can tell the GridFilter what filter to use for a specified key. However, as noted above, the number filter won't work, and the string filter won't work. But it's easy to build a custom filter.

A filter actually derives from a combo box. It associates text to select in the combo box with a function that compares what is in a cell of a DictionaryGrid with text that user inputs, x and y.

Using lambda functions, I can write some quite terse code to provide the functions:
class StartsWithNumberFilterCombo(gtk.ComboBox):
def __init__(self):

combo_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)
combo_store.append(["=",lambda x,y: convert_to_num(x) == float(y) ])
combo_store.append(["<",lambda x,y: convert_to_num(x) < float(y) ])
combo_store.append([">",lambda x,y: convert_to_num(x) > float(y) ])
combo_store.append(["<=",lambda x,y: convert_to_num(x) <= float(y) ])
combo_store.append([">=",lambda x,y: convert_to_num(x) >= float(y) ])
gtk.ComboBox.__init__( self, combo_store)
cell = gtk.CellRendererText()
self.pack_start(cell, True)
self.add_attribute(cell, 'text', 0)

def convert_to_num(string):
return float(string.split(" ")[0])
Note that if I need to do more complex transformations and/or comparisons, I could have used actually functions and passed the names of those functions in instead of using lambda functions.

Anyway, then I simply set up the filter hint when I create the GridFilter:
filter_hints = {"gravity":NumericFilterCombo(),"effected users":NumericFilterCombo(),
"status":StartsWithNumberFilterCombo(),"importance":StartsWithNumberFilterCombo()}
grid_filt = GridFilter(self.grid,filter_hints)
Presto-chango, I have a proper and custom filter for my DictionaryGrid, importance and status can be filtered numerically:

I think I shall simplify the creation of a custom filter somewhat by creating a FilterCombo class that you can derive from or that you can use stock and just stuff pairs of strings and functions into. Still, as is, this dramatically reduced the amount of time it took me to set up filters for the DictionaryGrid compared to if I used a stock Gtk TreeView.


About Quidgets
Quickly + Widgets = Quidgets
There is a Launchpad Project for Quidgets
The most up to date changes are in the Quidgets Trunk Branch
You can install Quidgets from the my PPA