Posts about python (old posts, page 32)

2010-07-24 20:37

This is why Qt (and PyQt) are cool

Alejandro Dolina once wrote (and this is from memory that's probably 25 years old) of a round table discussing "What's Tango?", and how after two hours of discussing the nature, characteristics and history of tango, one of the members of the panel picked up a bandoneón, played "El apache argentino" stood up and left without saying a word.

So, why are Qt and PyQt cool?

Audio player widget:

# -*- coding: utf-8 -*-

import sys, os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.phonon import Phonon
import icons_rc

class AudioPlayer(QtGui.QWidget):
    def __init__(self, url, parent = None):

        self.url = url

        QtGui.QWidget.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Preferred)


        self.player = Phonon.createPlayer(Phonon.MusicCategory,
            Phonon.MediaSource(url))
        self.player.setTickInterval(100)
        self.player.tick.connect(self.tock)

        self.play_pause = QtGui.QPushButton(self)
        self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))
        self.play_pause.clicked.connect(self.playClicked)
        self.player.stateChanged.connect(self.stateChanged)

        self.slider = Phonon.SeekSlider(self.player , self)

        self.status = QtGui.QLabel(self)
        self.status.setAlignment(QtCore.Qt.AlignRight |
            QtCore.Qt.AlignVCenter)

        self.download = QtGui.QPushButton("Download", self)
        self.download.clicked.connect(self.fetch)

        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.play_pause)
        layout.addWidget(self.slider)
        layout.addWidget(self.status)
        layout.addWidget(self.download)

    def playClicked(self):
        if self.player.state() == Phonon.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def stateChanged(self, new, old):
        if new == Phonon.PlayingState:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_pause.svg'))
        else:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))

    def tock(self, time):
        time = time/1000
        h = time/3600
        m = (time-3600*h) / 60
        s = (time-3600*h-m*60)
        self.status.setText('%02d:%02d:%02d'%(h,m,s))

    def fetch(self):
        print 'Should download %s'%self.url

def main():
    app = QtGui.QApplication(sys.argv)
    window=AudioPlayer(sys.argv[1])
    window.show()
    # It's exec_ because exec is a reserved word in Python
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Video player widget:

import sys, os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.phonon import Phonon
import icons_rc

class VideoPlayer(QtGui.QWidget):
    def __init__(self, url, parent = None):

        self.url = url

        QtGui.QWidget.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Preferred)


        self.player = Phonon.VideoPlayer(Phonon.VideoCategory,self)
        self.player.load(Phonon.MediaSource(self.url))
        self.player.mediaObject().setTickInterval(100)
        self.player.mediaObject().tick.connect(self.tock)

        self.play_pause = QtGui.QPushButton(self)
        self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))
        self.play_pause.clicked.connect(self.playClicked)
        self.player.mediaObject().stateChanged.connect(self.stateChanged)

        self.slider = Phonon.SeekSlider(self.player.mediaObject() , self)

        self.status = QtGui.QLabel(self)
        self.status.setAlignment(QtCore.Qt.AlignRight |
            QtCore.Qt.AlignVCenter)

        self.download = QtGui.QPushButton("Download", self)
        self.download.clicked.connect(self.fetch)
        topLayout = QtGui.QVBoxLayout(self)
        topLayout.addWidget(self.player)
        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.play_pause)
        layout.addWidget(self.slider)
        layout.addWidget(self.status)
        layout.addWidget(self.download)
        topLayout.addLayout(layout)
        self.setLayout(topLayout)

    def playClicked(self):
        if self.player.mediaObject().state() == Phonon.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def stateChanged(self, new, old):
        if new == Phonon.PlayingState:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_pause.svg'))
        else:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))

    def tock(self, time):
        time = time/1000
        h = time/3600
        m = (time-3600*h) / 60
        s = (time-3600*h-m*60)
        self.status.setText('%02d:%02d:%02d'%(h,m,s))

    def fetch(self):
        print 'Should download %s'%self.url

def main():
    app = QtGui.QApplication(sys.argv)
    window=VideoPlayer(sys.argv[1])
    window.show()
    # It's exec_ because exec is a reserved word in Python
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

...

2010-07-23 02:50

Desktop apps and clouds (with video)

I enjoy creating desktop applications. That means I may be a member of a dying breed, since web apps are going to make us all obsolete next week, but I do enjoy doing it.

The bad side of it is, of course that sometimes it's much more convenient to use a web application. For example, I have abandoned my own baby (uRSSus) because google reader is just easier and more convenient to use.

But then I thought... what bothers me of uRSSus? And there are quite a few things!

  1. It's not in all computers I may use

    That means I will not ever be able to use it exclusively.

  2. It's pretty useless without an Internet connection (but so is google reader mostly)

  3. Since I can't use it exclusively, I end with feeds on uRSSus that are not on google reader and viceversa.

  4. It's freaking slow

So, I decided to see what I could do about that without giving up the good side of uRSSus:

  1. It looks much nicer than a web app, because it looks like a desktop app
  2. It does things like opening the site instead of showing the feed item (great for partial content feeds)
  3. I wrote it (yes, that's a feature for me. I like self-made programs)

So, this attempt at rewriting the desktop RSS reader produced this:

As you can see in the above video, this reader syncs the subscription list to google reader. It will also eventually sync your read/unread posts.

It still can open full sites instead of feed items, it has/will have a heck of an offline mode (full pages captured as images, for example), and... it's very very fast.

It's much faster than google reader in Chromium, and hella faster than uRSSus. That was done via smarter coding, so it probably means I was braindead before and experienced a minor recovery.

The code is not fit for release (for example, the database schema will change) but you can try it: http://code.google.com/p/kakawana/source/checkout

2010-07-17 03:53

Slow-Slow and Fast-Fast (video)

My previous post explained how to cache whole web pages as images. Now see it in action. This is a lightweight RSS reader, optimized for comic books (but it works for any feed) and for offline use (but it works online too, of course).

Not ready for public use yet, but if you look around you can find the code somewhere ;-)

2010-07-16 19:58

Capturing a webpage as an image using Pyhon and Qt

For a small project I am doing I wanted the capability to see web pages offline. So, I started thinking of a way to do that, and all solutions were annoying or impractical.

So, I googled and found CutyCapt which uses Qt and WebKit to turn web pages into images. Good enough for me!

Since I wanted to use this from a PyQt app, it makes sense to do the same thing CutyCapt does, but as a python module/script, so here's a quick implementation that works for me, even if it lacks a bunch of CutyCapt's features.

With a little extra effort, it can even save as PDF or SVG, which would let you use it almost like a real web page.

You just use it like this:

python  capty.py http://www.kde.org kde.png

And here's the code [download capty.py]

# -*- coding: utf-8 -*-

"""This tries to do more or less the same thing as CutyCapt, but as a
python module.

This is a derived work from CutyCapt: http://cutycapt.sourceforge.net/

////////////////////////////////////////////////////////////////////
//
// CutyCapt - A Qt WebKit Web Page Rendering Capture Utility
//
// Copyright (C) 2003-2010 Bjoern Hoehrmann <[email protected]>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// $Id$
//
////////////////////////////////////////////////////////////////////

"""

import sys
from PyQt4 import QtCore, QtGui, QtWebKit


class Capturer(object):
    """A class to capture webpages as images"""

    def __init__(self, url, filename):
        self.url = url
        self.filename = filename
        self.saw_initial_layout = False
        self.saw_document_complete = False

    def loadFinishedSlot(self):
        self.saw_document_complete = True
        if self.saw_initial_layout and self.saw_document_complete:
            self.doCapture()

    def initialLayoutSlot(self):
        self.saw_initial_layout = True
        if self.saw_initial_layout and self.saw_document_complete:
            self.doCapture()

    def capture(self):
        """Captures url as an image to the file specified"""
        self.wb = QtWebKit.QWebPage()
        self.wb.mainFrame().setScrollBarPolicy(
            QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
        self.wb.mainFrame().setScrollBarPolicy(
            QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)

        self.wb.loadFinished.connect(self.loadFinishedSlot)
        self.wb.mainFrame().initialLayoutCompleted.connect(
            self.initialLayoutSlot)

        self.wb.mainFrame().load(QtCore.QUrl(self.url))

    def doCapture(self):
        self.wb.setViewportSize(self.wb.mainFrame().contentsSize())
        img = QtGui.QImage(self.wb.viewportSize(), QtGui.QImage.Format_ARGB32)
        painter = QtGui.QPainter(img)
        self.wb.mainFrame().render(painter)
        painter.end()
        img.save(self.filename)
        QtCore.QCoreApplication.instance().quit()

if __name__ == "__main__":
    """Run a simple capture"""
    app = QtGui.QApplication(sys.argv)
    c = Capturer(sys.argv[1], sys.argv[2])
    c.capture()
    app.exec_()

2010-07-16 17:14

Learn python! For free! With me! (in part)

I'm one of the speakers for the free python courses in FM La Tribu, in Buenos Aires.

Every saturday you can learn something from one of the best python programmers in a thousand miles, or from me.

I'll be teaching about virtualenv, buildout, nose and other things on August 21, about GUI stuff on September 25 and October 2, and about PyQt in October 30.

This is all for free, and I hope lots of people show up!

The full schedule is here.

2010-06-18 15:42

Free software is good for me.

I make a living working with free software (BTW, if you need sysadmins that know what they do, contact us: http://www.netmanagers.com.ar)

But that's not that big a deal, I could make a living doing something else. I am sure I would be competent at something else, even if I have no idea what that would be right now.

It does, however give me freedom to play, which is much more important. Therefore, this post is sort of a status update on things I play with. Not games, those are not really my thing, but things that I do for fun.

Yes, some of these may mean I am a very strange person.

I'll limit myself to the last couple of weeks or so.

There's been sort of a bump in interest in Marave, my distraction free editor and it's because it has been reviewed in Linux Journal!

I have read the article (sadly I can't link to it) and it was a super positive review, here are some choice quotes:

"marave makes the dull world of text editing romantic and immersive with beautiful minimalism"

"... it doesn't just have minimalism and simplicity, it has minimalism and simplicity combined with beauty and a palpable design ethic. marave has soul, and I love that."

So thanks for the kind words to the author, and something I noticed: you ran into a big bug in marave and didn't notice :-)

The "cricket bat" icon (it's a screwdriver ;-) should show you the config dialog. However, it seems in Ubuntu (and maybe in other distros, I don't know) the config is not visible,and all you see is the text move around a bit. This is what he should have seen:

marave15

I have never been able to reproduce it, but I am going to install a Ubuntu VM just for this, so maybe soon.

On related news, marave was also reviewed in a german magazine a couple of months ago, and I have not been able to get a copy of the article. (BTW, isn't it reasonable to send a copy of these to the author of the program you are reviewing? Neither magazine even mentioned it to me!)

In any case, if anyone has this magazine and can tell me what the article about distraction-free editors say, you will make my day:

Here's the article teaser

And this seems to be the magazine issue:

https://shop.linuxnewmedia.de/store/eh01/EH10165/de/product_image/variant/bounding_product

On new projects (yes, I always have new projects), I ran into this awesome blog post by Roger Alsing about approaching Mona Lisa with just 50 polygons <http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/ > and being a nerd and having awesome programming tools at my command... I wrote a framework to test that kind of algorithms.

I called it evoluto and it's at http://evoluto.googlecode.com.

I only did a very simple algorithm, based on transluscent triangles, but it did work... for some definition of work!

You can even see the local minimum that doesn't let her right eye form right :-)

Evoluto has a library of algorithms (currently empty) and you can edit and reapply on-the-fly the one you want, and see the generations change on-screen.

It would take some work to make it a polished program, but it does work.

I folled around a bit with creating a nice PDF presentation player but it's still very early:

109301062

In what's perhaps my most established project, rst2pdf. I have fixed a bunch of bugs, and a release is a bit overdue:

Issue 186: Text not wrapping around images when specified
I fixed this by adding a new CLI option, so behaviour was not changed, but now you can have images with text flowing beside it. It will not look great but it works.
Issue 307: Replace directive doesn't replace text in header/footer in some cases
This was an interesting problem! It was very entertaining.
Made it work with Sphinx 1.*
There is a piece broken still, but what I fixed was not terribly hard.
Unbroken bookrest
I need to work much more with this, but at least what worked before works again. If you don't know what bookrest is, it's a rst2pdf graphical frontend / word processor, here's a taste:

I also made several releases for my AUR packages

Plus I worked, and some other stuff. All in all, not a bad stretch.

2010-06-03 13:21

Random photos from my phone

A few days ago I finally got my 89 cents bluetooth dongle (now $1.85, but still with free shipping from china!) and got a bunch of pictures I had in my phone.

The quality is crap because my phone is crap, but trust me, there must be one thing here you have never seen before.

Here they are: weird stuff that made me take out my phone and grab a picture, with explanations.

Titanic

This, from Mar del Plata, is the most badass popup book I ever saw.

Closed:

Imagen033

And open:

Imagen032

I'm Mark Shuttleworth!

Imagen024 Imagen025

In a free software event in Buenos Aires, Canonical's boss and former space cargo was supposed to deliver the keynote. He canceled at the last minute. So Maddog Hall offered to replace him... in character.

Someone found a really, really awesome (and/or crappy!) astronaut costume, and Maddog gave a keynote shouting "I'm Mark Shuttleworth! I'm an astronaut!" and claiming to have come from the future to examine some slides recently found, written by some unknown dude named Maddog. Really funny stuff.

Python vs. Ruby

Same event, take a look:

Imagen023 Imagen022

Yes, I swear they are taken with less than 10 seconds of one another.

Butter

Imagen018 Imagen026

I was buying groceries in San Isidro's Disco supermarket. Yes, usually buying a large package of butter is cheaper per kilo than a small one. But here, a 200g package costed almost the same as a 100g! That's just stealing money from those who don't use much butter. Me? I'm not at risk.

Visa discount!

Imagen045

This was a shop in Avenida Alem in Buenos Aires. It was unusual to see a "VISA is suspended, 20% discount" sign. Much more unusual was to see the small letters: "present your visa card". I mean, wasn't it suspended?

And then I saw the rest:

Imagen046

It says "present your visa card and pay using anything else".

That guy must really have been pissed off at Visa!

I got a bunch more for some other time.

2010-05-12 20:08

What's wrong with this dialog?

I am writing a book. And I am writing a chapter about UI design. And why not use the Internet?

So, go ahead and tell me all that's wrong with this dialog!

radio-14

For example, I don't like the dead space at the bottom-left, the different-size of the "Close" button, and the misalignment of the icons.

Are those valid concerns? Are there many more? Would you do it completely different?

The book is open source, and available at http://nomuerde.netmanagers.com.ar (In spanish, sorry!)

2010-04-11 05:12

I am posting very little because I am writing a lot.

I am just not writing here. I am writing a book instead.

What book am I writing? A book about python programming, of course! It's called "Python No Muerde" (Python Doesn't Bite) and it's in spanish.

Now, I am the first to admin: I am not a great programmer. And I am not a great writer. But I have lots of things to say. If I can organize them correctly, they even make sense sometimes!

So, I am giving this write-long-stuff thing a try.

Of course since I am an open source nerd, I can't do things the usual way, therefore, the book is under Creative Commons. And because I am a programmer, I hacked together a (if I may say so myself) decent structure to handle book-writing.

  1. I write in restructured text
  2. I use rst2pdf to create PDFs both of individual chapters and the whole thing.
  3. I use rest2web to create a website
  4. I use mercurial (at googlecode) to handle revision control and history.
  5. I use make to control rebuilding of chapters when code changes, or images get updated, etc.

Of course it's more complicated than that, the PDFs are in the site, the site is uploaded via rsync, the uploads and rebuilds are triggered by hg push, and so on.

In any case, I may post a few times about how this whole thing works, here is the output of the machinery:

http://nomuerde.netmanagers.com.ar

Contents © 2000-2018 Roberto Alsina