Posts Tagged ‘Python’

(on Technorati , Del.icio.us)

python treeview toggle

Had this post sitting around. Seems finished. May be helpful to someone. /me waves Wand of Publish +1

I was confused when I was playing around with this basic concept: adding a toggle widget to the treeview in pygtk. The reason for this is an inconsistency in the api model – or at least how I perceived it. With a regular toggle button, you create the widget and can manipulate it once it is drawn. The checkmark is toggled and the “toggled” signal is emitted. I only connect a signal handler to the toggled signal after. However, following this same logic, I created a list with a column of toggle widgets and tried clicking them… but nothing happened. The problem here was the toggled value was linked to the list’s data, and the data wasn’t actually changing. Even though the toggle signal was being emitted, the checkmark wasn’t being toggled because the data wasn’t changing, so I thought there was a problem with my code and the signal wasn’t being emitted. But actually, it would make more sense if it was a “clicked” signal that was being emitted, not the “toggled” signal.

Example source code:

#!/usr/bin/env python
 
# example basictreeviewtoggle.py
 
import pygtk
pygtk.require('2.0')
import gtk
import gobject
 
class BasicTreeViewToggleExample:
 
    # close the window and quit
    def delete_event(self, widget, event, data=None):
        gtk.main_quit()
        return False
 
    def column_toggled(self, cell, path, model):
        # get toggled iter, and value at column 0
        iter = model.get_iter((int(path),))
        val = model.get_value(iter, 0)
 
        # toggle the value
        val = not val
 
        # set new value
        model.set(iter, 0, val)
 
 
    def __init__(self):
        # create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title("Basic TreeView Toggle Example")
        self.window.set_size_request(200, 200)
        self.window.connect("delete_event", self.delete_event)
 
        # create a ListStore with two columns to use as the model
        self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, str)
 
        # create some list items
        for item in range(5):
            self.model.append([False, 'item %i' % item])
 
        # create the TreeView using the model
        self.view = gtk.TreeView(self.model)
 
        # create a CellRendererText to render the data
        self.cellrenderer_text = gtk.CellRendererText()
        self.cellrenderer_toggle = gtk.CellRendererToggle()
        self.cellrenderer_toggle.connect('toggled', self.column_toggled, self.model)
 
        # create the TreeViewColumns to display the data
        self.tvcolumntext = gtk.TreeViewColumn('TreeViewColumn 1')
        self.tvcolumntoggle = gtk.TreeViewColumn('tog', self.cellrenderer_toggle, active=0)
 
        # add the TreeViewColumns to the TreeView
        self.view.append_column(self.tvcolumntoggle)
        self.view.append_column(self.tvcolumntext)
 
 
 
 
        # add the cell to the tvcolumn and allow it to expand
        self.tvcolumntoggle.pack_start(self.cellrenderer_toggle, False)
        self.tvcolumntext.pack_start(self.cellrenderer_text, True)
 
 
        # set the cell "text" attribute to column 0 - retrieve text
        # from that column in treestore
        self.tvcolumntext.add_attribute(self.cellrenderer_text, 'text', 1)
 
 
 
        # make it searchable
        self.view.set_search_column(1)
 
        # Allow sorting on the column
        self.tvcolumntext.set_sort_column_id(1)
 
        # Allow drag and drop reordering of rows
        self.view.set_reorderable(True)
 
        self.sw = gtk.ScrolledWindow()
        self.sw.add(self.view)
        self.window.add(self.sw)
 
        self.window.show_all()
 
def main():
    gtk.main()
 
if __name__ == "__main__":
    tvexample = BasicTreeViewToggleExample()
    main()

AttrDict Python Module

I’ve been doing quite a bit of Python hacking in my recent free time. A couple days ago, I had the desire for a dictionary that I could access key values just like object attribute names. For example, in the dictionary d={'key':'value'}, I wanted to be able to use d.key to return 'value'. I thought this would be a common desire and probably already exists (and might even be built-in somehow), so I went on to #python and asked the folk there. Nobody knew of anything. So I set off to write my own. I called it AttrDict.

Yesterday, I found something similar already exists. It’s called ObDict. Similar? Very! :P But different enough that I continued mine… and have a somewhat complete python module of my own. So far it’s been a nice opportunity to learn more about Python objects and use the unittest module for unit testing.

It’s not 100% coverage of the dict interface, but it’s pretty close and I think it’s usable enough that I can slap a quick release together and work on other stuff. Bugs/patches/testing/suggestions welcome.

Update:

Wooops, forgot to write a bit more about it. Here’s the docstring from the module:

Simple extension of the built-in dictionary so that dictionary keys are mirrored
as object attributes. This is for convenience. You can do things like this:

d = dict() #standard dict, for comparison
a = AttrDict() #

d['ok'] = ‘this is ok’
d.ok -> AttributeError raised
d.ok = ‘test’ -> AttributeError raised

You cannot assign attributes to standard Python dicts.

a['ok'] = ‘this is ok’
a.ok -> ‘this is ok’ #attribute is automatically created
a.ok = ‘changed’
a['ok'] -> ‘changed’ #and the dict value is automatically updated
a.ok2 = ‘new value’ #adding new attribute, ok2
a['ok2'] -> ‘new value’ #dict key is automatically created

This introduces a limitation on the dictionary keys such
that they must be strings and provide valid Python syntax for accessing.

For example:

{’123′:’valid’} #is a valid dictionary

but

mydict.123 #is not valid Python syntax.

Attempting to create a key that cannot be accessed through an attribute name
will raise an AttributeError Exception.

This module has not been built for optmization. Some of the method
documentation has been taken from Python’s dict documentation. For more info
on a particular method, refer to that. I’ve tried to mirror the effects of
the standard dict as closely as possible.

Snakes in an Office

I’ve mentioned before that my job (whose contract is almost up) doesn’t require programming. But that doesn’t mean that programming is not useful. When I first got my laptop, I asked the tech guy about the process of installing new software. It went something like this:

  1. Write a formal request for the software you would like installed and submit it to the tech support department.
  2. Wait for review and approval.
  3. Wait for them to install it.

A pretty standard (and painful) process in large organizations, unfortunately. I asked him, “So if I want to install Python I just submit one of these requests?”

Insead of answering my question, he asked me one in return. “What would you want to install Python for?!” I think he actually spat and curled his lips at the thought.

“I don’t know… writing basic scripts.” I really didn’t know what at the time, but I knew it would be useful. And I wanted to use it.

He proceeded to look at me as if I had suggested bathing in tomato sauce as a remedy for headaches.

So I was under the impression that I couldn’t install new software and didn’t want to bother going through all that formal cock holding; I went without my Firefox, my Python. I’ve since discovered that I can install things. (Sorta.)

Anyway, I was using Python at work today, and I just love it. Previously, I had been fumbling around with VBA in Excel and Word. I had a button set up in Word that would run a macro/VBA to export the form’s contents to a CSV file in a particular folder. I could open a Word document anywhere, press the export button, and the CSV would be created/overwritten in that folder. Then I had a button set up in Excel to run a macro that would import all CSV files in that folder as rows in the spreadsheet. (This was actually really useful, and if you have to deal with a lot of similar tasks in Office, use VBA and macros.) There was an inconsistency in the number of rows I had in my spreadsheet and the number of docs I had… so I wanted to compare the exported CSVs with the available DOCs.

Enter, the Python interpreter (great for little tasks and as a substitute shell on windows).

The word documents were in a bunch of different folders (for various reasons) but once I had a variable, originals, containing a list of all the documents, and a variable, exported, containing a list of all the CSV, files, I was rolling.


>>> len(originals), len(exported)
(198,200) # Hmmmm, looks like a job for sets!
>>> s1,s2 = (set(originals), set(exported))
>>> len(s1.difference(s2))
398
>>> # What the...
...
>>> originals
['doc1.doc', 'doc2.doc', ...., 'doc200.doc']
>>> exported
['doc1.txt', 'doc2.txt', ..., 'doc200.txt']
>>> # Oh yeah, different extensions. Duh...
... # Bus leaves SOON!
... # Need to quickly strip the extensions and rebuild the sets....
...
>>> s1,s2 = ( set([s[:-4] for s in s1]), set([s[:-4] for s in s2]) )
>>> s1
['doc1', 'doc2', ... , 'doc200']
>>> # Cool
...
>>> s1.difference(s2)
(['doc38', 'doc72'])

AHA!! Caught my bus. Python is great. :D

Rhythmbox Jump-to-playing Plugin

This plugin will display the View : Jump to Playing Song link as a button in the toolbar and as link in the Browser’s context menu. This is about as simple as a plugin could be (which is partly why I wrote it), but I’ve actually found it quite useful. Maybe you will too.

jump-to-playing-0.1

Download

jump-to-playing-0.1.tar.gz (Update: Newer version is available.)

Installation

  1. Extract the jump-to-playing folder into your ~/.gnome2/rhythmbox/plugins/ directory.
  2. (Re)Start Rhythmbox and enable the plugin in Edit : Plugins.

Todo

  • Add Configure dialog with checkboxes for toolbar and browser context menu, defaulting to toolbar only (both is a little redundant). Currently, both are added automatically.
    [x] Add button to toolbar
    [_]Add link to browser context menu
  • Force “Properties” to bottom of browser context menu (may depend on placeholder being added to the context menu)
  • Hide toolbar button in Small Display mode.

Getting Tabs Closed

You know you’re trying to do too many things at once when…

ZOMG that’s a lot of tabs!

Managing browser tabs needs its own methodology, like GTD: Every week, go through your open tabs and close as many as you can. I don’t actually need to read that article. Not interested in this, any more. etc.

A bit better…  :-/

Clearly, I fail. >.< Restoring this session of 20 tabs brings Firefox up to 80MB, right away. Most of my current tabs are about different programming things: various references, tutorials, articles… as well as a tab to feedburner – for some reason, I’m addicted to looking at my blog’s meagre statistics. It’s fun!

Side Note: One thing that’s pretty cool, that can help minimize the tabs open for Python reference, is the Python sidebar. If there was only a pyGTK section in the sidebar….

When I’ve had tabs sitting open with no activity… I copy the link into a “would-be-nice” Tomboy note and close the tab. This helps a little… but I still have generally too many tabs open to help with the task at hand – and I prefer tabs to new windows (opening new windows is painfully slow on my setup, not sure why). If you have a similar problem of many tabs open at one time, I highly recommend the Tab Groups Firefox extension. Take a look:

Tab Groups Firefox Extension

Wow. The extension is still super early (I think it’s already caused FF to crash once), it takes a little while to sort the tabs when restoring a session, and you can’t move the Tab Groups around… but I’m definitely going to continue using it. It allows for much easier navigation of your current session, rather than scroll-click-is-this-what-i’m-looking-for-if-not-repeat. And for some reason, it even feels snappier! :o So this helps you Get Tabs Organized, which helps GTC, which helps GTD. Yay. :)

PhotoFile

Screenshot update! Still no version… as it’s still just a husk of a UI… mostly.

PhotoFile pre versioning

I’ve changed the GUI quite a bit. Actually, what it is now took a surprisingly long time to arrive at. I spent time going through some ideas on paper, and I even did a huge amount of refactoring to make coding easier. It’s at the point where a GUI in another API could easily be thrown in…. it just requires me separating the PhotoFile class into PhotoFile and PhotoFileGTK… but I’m not going to bother, at this point, because I don’t think there’s much point in offering it in another kit. GUI and no-GUI could be useful, though. Anyway, there’s still quite a few problems remaining, including:

  1. Supported File Types: I need a list of file types (extensions) that are common in Cameras and that people would be interested in transferring. So far, I’ve got what my camera supports: JPG, THM, AVI, and WAV. Some cameras allow for sound recordings to be created (WAVs on mine) but I’m not sure what I should do with these… rename to have the same name as the image, I guess (if it’s a memo). Post your camera’s formats and how they’re used in the comments! Example of my Camera: WAV files with a filename the same as an image are a sound memo for that image. AVIs are movies and have and accompanying THM file (same filename) which is a small Jpeg containing a thumbnail of the movie.
  2. Empty Source Directories: When moving files from the source, should I automatically remove any empty source directories? Maybe add an advanced property for this? I certainly don’t want to add it to the main dialog. KISS.
  3. Separate Operations: I’m not sure if each file should save it’s own set of operations for the session. For example, user selects manual rotation for two files, and auto-rotation for the rest. Should Process All Files remember those two files’ manual rotation, or should it apply the visible operations to ALL files. If I should save settings for each file, then I feel like I’d need another button, Process All Files Using These Operations, just to be clear… maybe a “Reset to defaults” somewhere… sounds like too much clutter, but it could be useful for people whose camera’s don’t store EXIF. Suggestions?
  4. Manual Rotation: Need a dropdown or something for Manual rotation! Probably: {Left, Right, 180} or… a button Rotate 90 CW that when clicking, rotates the preview 90 degrees, clockwise. I kind of like that idea… super simple. To rotate “left”, the user would quickly learn that 3 quick clicks is quite fast.
  5. White Space: I think I need a little more white-space between the different sections.
  6. Functionality!
  7. Camera’s dying? Oh noes! I love my Canon IXY 400, but I’ve recently been getting a very ominous Memory Card Error message, more frequently. It worries me.

Aside from these things, I think I’m pretty satisfied with the current UI.

Still a tiny app, and still lots of things to do! :D


$ cat photofile.py | wc -l
792
$ cat photofile.py | grep FIXME | wc -l
25