29a.ch

Entries tagged “python”

Atomic get and increment in python

For generating continuous unique id's in python I needed a thread safe way to do this:
x = counter
counter += 1
When disassembling this code we will get this:
  2           0 LOAD_FAST                0 (counter)
              3 STORE_FAST               1 (x)

  3           6 LOAD_FAST                0 (counter)
              9 LOAD_CONST               1 (1)
             12 INPLACE_ADD         
             13 STORE_FAST               0 (counter)
As you can see not even counter += 1 is atomic. Now the obvious solution would be to use a lock. The not so obvious solution is to use a itertools.count(). The counter is implemented in C and doesn't release the GIL so it is atomic. The code would the look like this:
x = counter.next()
which is more pretty anyway.

PyGST messing with sys.argv

While developing play it slowly I noticed some strange behavior of the python gstreamer bindings. For some reason pygst parses argv on import. This illustrates the problem:
[veers@castle ~]$ python
Python 2.6.1 (r261:67515, Dec  7 2008, 08:27:41) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys.argv
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named argv
>>> import sys
>>> sys.argv.append("--help")
>>> import gst
Usage:
  . [OPTION...] - GStreamer initialization

Help Options:
  -?, --help                        Show help options
  --help-all                        Show all help options
  --help-gst                        Show GStreamer Options
That's not nice of you pygst! But there's a simple workaround:
argv = sys.argv
sys.argv = []
import gst
sys.argv = argv
I guess I should write a patch instead of a post but.. may be later.

Play it slowly 1.1

And there it is, a new version of play it slowly. It fixes all known bugs and even adds some features

  • Saving of state (file, speed, ..)
  • Improved error handling
  • Pitch scale is using semitones
  • Speed scale allows steps of 0.05
  • New command line argument --sink
  • Fixes all known bugs

If you've got suggestions please write a comment

screenshot

Get it Now

PyGTK Exception Hook

screenshot I wrote a little exception hook for pygtk applications. When an exception occurs it will show a dialog with a full stack trace obtained using cgitb.

import gtk, gobject
import sys

_ = lambda s: s

def scrolled(widget, shadow=gtk.SHADOW_NONE):
    window = gtk.ScrolledWindow()
    window.set_shadow_type(shadow)
    window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    if widget.set_scroll_adjustments(window.get_hadjustment(),
                                      window.get_vadjustment()):
        window.add(widget)
    else:
        window.add_with_viewport(widget)
    return window


class ExceptionDialog(gtk.MessageDialog):
    def __init__(self, etype, evalue, etb):
        gtk.MessageDialog.__init__(self, buttons=gtk.BUTTONS_CLOSE, type=gtk.MESSAGE_ERROR)
        self.set_resizable(True)
        self.set_markup(_("An error has occured:\n%r\nYou should save "
                "your work and restart the application. If the error "
                "occurs again please report it to the developer." % evalue))
        import cgitb
        text = cgitb.text((etype, evalue, etb), 5)
        expander = gtk.Expander(_("Exception Details"))
        self.vbox.pack_start(expander)
        textview = gtk.TextView()
        textview.get_buffer().set_text(text)
        expander.add(scrolled(textview))
        self.show_all()

def install_exception_hook(dialog=ExceptionDialog):
    old_hook = sys.excepthook
    def new_hook(etype, evalue, etb):
        if etype not in (KeyboardInterrupt, SystemExit):
            d = dialog(etype, evalue, etb)
            d.run()
            d.destroy()
        old_hook(etype, evalue, etb)
    new_hook.old_hook = old_hook
    sys.excepthook = new_hook

if __name__ == "__main__":
    install_exception_hook()
    gobject.idle_add(lambda: 1/0)
    gobject.idle_add(gtk.main_quit)
    gtk.main()

Stepped scales with pygtk

The Scale Widgets that come with gtk ignore step_incr from the adjustment when the user drags the slider. So there is no way to specify that you only want to use increments of 0.5 or 1.0. So here's how to do it:

class Scale(object):
    """A scale that adheres to increment steps"""
    def __init__(self):
        self.connect("change-value", self.adjust)

    def adjust(self, range, scroll, value):
        adj = self.get_adjustment()
        lower = adj.get_property('lower')
        upper = adj.get_property('upper')
        incr = adj.get_property('step-increment')
        value -= (value % incr)
        self.set_value(min(max(lower, value), upper))
        return True


class VScale(gtk.VScale, Scale):
    def __init__(self, *args):
        gtk.VScale.__init__(self, *args)
        Scale.__init__(self)

class HScale(gtk.HScale, Scale):
    def __init__(self, *args):
        gtk.HScale.__init__(self, *args)
        Scale.__init__(self)
Author

Jonas Wagner Jonas Wagner
Software Engineer
Zürich, Switzerland

More about me

Follow 29a_ch on Twitter

Experiments

screenshot screenshot screenshot screenshot

More Experiments

Latest Posts Tags Archive Links

guitarmasterclass.net (guitar lessons)