December 9, 2009

Python 3 - tkinter (Tk Widgets) - BusyBar Busy Indicator

Here is another example GUI application using Python 3.1.

For this example, I used BusyBar.py, a module for creating a "busy indicator" (like the knight-rider light). To do this, I first had to port BusyBar to Python 3.1 from 2.x. The new code for this module can be found here:

BusyBar.py

It renders on Ubuntu (with Gnome) like this:

Code:

#!/usr/bin/env python
# Python 3


import tkinter
from tkinter import ttk
import BusyBar


class Application:
    def __init__(self, root):
        self.root = root
        self.root.title('BusyBar Demo')
        ttk.Frame(self.root, width=300, height=100).pack()
        
        bb = BusyBar.BusyBar(self.root, width=200)
        bb.place(x=40, y=20)
        bb.on()
    

if __name__ == '__main__':
    root = tkinter.Tk()
    Application(root)
    root.mainloop()

December 8, 2009

Python 3 - tkinter ttk (Tk Themed Widgets) - Blocking Command Example

Here is another example GUI application with ttk in Python 3.1.

This example shows usage of the Button, Text, and Scrollbar widgets, along with some basic layout management using grid().

To use it, enter a URL and click the button. It will send an HTTP GET request to the URL and insert the response headers into the Text widget. You will notice that the GUI is blocked (frozen) while the URL is fetched. This is because all of the work is done in the main event thread. I will show how to use threads for non-blocking events in a future post.

It renders on Ubuntu (with Gnome) like this:

Code:

#!/usr/bin/env python
# Python 3


import tkinter
from tkinter import ttk
import urllib.request



class Application:
    def __init__(self, root):
        self.root = root
        self.root.title('Blocking Command Demo')
        
        self.init_widgets()
            
            
    def init_widgets(self):
        self.btn = ttk.Button(self.root, command=self.get_url, text='Get Url', width=8)
        self.btn.grid(column=0, row=0, sticky='w')
        
        self.entry = ttk.Entry(self.root, width=60)
        self.entry.grid(column=0, row=0, sticky='e')
        
        self.txt = tkinter.Text(self.root, width=80, height=20)
        self.txt.grid(column=0, row=1, sticky='nwes')
        sb = ttk.Scrollbar(command=self.txt.yview, orient='vertical')
        sb.grid(column=1, row=1, sticky='ns')
        self.txt['yscrollcommand'] = sb.set
        

    def get_url(self):
        url = self.entry.get()
        headers = urllib.request.urlopen(url).info()
        self.txt.insert(tkinter.INSERT, headers)
    
    

if __name__ == '__main__':
    root = tkinter.Tk()
    Application(root)
    root.mainloop()

December 7, 2009

Python 3 - tkinter ttk (Tk Themed Widgets) - Button/Text Example

Here is some boilerplate code for setting up a basic GUI application with ttk in Python 3.1.

This example shows usage of the Frame, Button, and Text widgets. When you click the button, "Hello World" is inserted into the Text widget.

#!/usr/bin/env python
# Python 3


import tkinter
from tkinter import ttk


class Application:
    def __init__(self, root):
        self.root = root
        self.root.title('Button Demo')
        ttk.Frame(self.root, width=250, height=100).pack()
        
        self.init_widgets()
            
    def init_widgets(self):
        ttk.Button(self.root, command=self.insert_txt, text='Click Me', width='10').place(x=10, y=10)
        self.txt = tkinter.Text(self.root, width='15', height='2')
        self.txt.place(x=10, y=50)
        
    def insert_txt(self):
        self.txt.insert(tkinter.INSERT, 'Hello World\n')


if __name__ == '__main__':
    root = tkinter.Tk()
    Application(root)
    root.mainloop()

It renders on Ubuntu (with Gnome) like this:

December 6, 2009

Python 3 - tkinter ttk (Tk Themed Widgets) - GUI Hello World

Here is some boilerplate code for setting up a basic GUI application with ttk in Python 3.1:

#!/usr/bin/env python
# Python 3


import tkinter
from tkinter import ttk

class Application:
    def __init__(self, root):
        self.root = root
        self.root.title('Hello World')
        ttk.Frame(self.root, width=200, height=100).pack()
        ttk.Label(self.root, text='Hello World').place(x=10, y=10)

if __name__ == '__main__':
    root = tkinter.Tk()
    Application(root)
    root.mainloop()

This example shows usage of the Frame and Label widgets, and some basic layout management using pack() and place(). It renders on Ubuntu (with Gnome) like this:

December 3, 2009

Python - Accurate Cross Platform Timers - time.time() vs. time.clock()

In Python, you can add simple timers around any action using the clock() or time() functions from the time module. time.clock() gives the best timer accuracy on Windows, while the time.time() function gives the best accuracy on Unix/Linux. You should use whichever one is more appropriate for your system.

Inside the timeit module's source code (in Python's standard library), you can see an example of this. The timer type is specified by the platform:

if sys.platform == "win32":
    # On Windows, the best timer is time.clock()
    default_timer = time.clock
else:
    # On most other platforms, the best timer is time.time()
    default_timer = time.time

This seems like a nice way to create a timer that is accurate on either platform.

Here is an example:

import sys
import time

# choose timer to use
if sys.platform.startswith('win'):
    default_timer = time.clock
else:
    default_timer = time.time

start = default_timer()
# do something
finish = default_timer()
elapsed = (finish - start)

October 23, 2009

Linus on Evolution

Here is a great rant from Linus Torvalds back in 2002 on biological and software evolution.
... from a thread on LKML, summarized here: http://kerneltrap.org/node/11


You know what the most complex piece of engineering known to man in the whole solar system is?

Guess what - it's not Linux, it's not Solaris, and it's not your car.

It's you. And me.

And think about how you and me actually came about - not through any complex design.

Right. "sheer luck".

Well, sheer luck, AND:

  • free availability and _crosspollination_ through sharing of "source code", although biologists call it DNA.
  • a rather unforgiving user environment, that happily replaces bad versions of us with better working versions and thus culls the herd (biologists often call this "survival of the fittest")
  • massive undirected parallel development ("trial and error")

I'm deadly serious: we humans have _never_ been able to replicate something more complicated than what we ourselves are, yet natural selection did it without even thinking.

Don't underestimate the power of survival of the fittest.

And don't EVER make the mistake that you can design something better than what you get from ruthless massively parallel trial-and-error with a feedback cycle. That's giving your intelligence _much_ too much credit.



Linus

October 19, 2009

Python - URL Timer - Web Monitor Utility

In a previous post, I showed how to insert timers between steps in an http request to do some basic profiling. Peter Bengtsson contacted me with some enhancements to the original code. I took his enhancements and added some more of my own to create a neat little web monitoring utility.

It uses Python's httplib to send a GET requests at regular intervals to a URL and adds some timing instrumentation between each step of the request/response. Results are printed to the console.

get it here:
http://code.google.com/p/corey-projects/source/browse/trunk/python2/url_timer.py

to use, give it a site and interval:

> python url_timer.py www.goldb.org 5

... or an https/ssl url and an interval:

> python url_timer.py https://ssl.sonic.net/ 5

sample output:

>python url_timer.py www.goldb.org 5
request sent         response received    content transferred  size
------------         -----------------    -------------------  ----
0.0040 (0.0040)      0.2830 (0.2830)      0.2846 (0.2846)      9810 bytes (0.010 MB total)
0.0009 (0.0024)      0.2790 (0.2810)      0.2803 (0.2825)      9810 bytes (0.020 MB total)
0.0009 (0.0019)      0.2841 (0.2821)      0.2854 (0.2834)      9810 bytes (0.029 MB total)
0.0010 (0.0017)      0.2775 (0.2809)      0.2789 (0.2823)      9810 bytes (0.039 MB total)
0.0008 (0.0015)      0.2794 (0.2806)      0.2820 (0.2822)      9810 bytes (0.049 MB total)
0.0009 (0.0014)      0.2845 (0.2813)      0.2859 (0.2828)      9810 bytes (0.059 MB total)
0.0010 (0.0013)      0.2796 (0.2810)      0.2809 (0.2826)      9810 bytes (0.069 MB total)
0.0009 (0.0013)      0.2798 (0.2809)      0.2808 (0.2823)      9810 bytes (0.078 MB total)
0.0009 (0.0012)      0.2791 (0.2807)      0.2803 (0.2821)      9810 bytes (0.088 MB total)
...

October 5, 2009

Automated Web/HTTP Profiler with Selenium-RC and Python

A small new open source project I am working on:

Selenium-profiler is a web/http profiler built with Selenium-RC and Python. It profiles page load time and network traffic for a web page. The profiler uses Selenium-RC to automate site navigation (via browser), proxy traffic, and sniff the proxy for network traffic stats as requests pass through during a page load.

It is useful to answer questions like:

  • how many http requests does that page make?
  • how fast are the http responses coming back?
  • which http status codes are returned?
  • how many of each object type are requested?
  • what is the total page load time?

Get it here:
http://selenium-profiler.googlecode.com/

Sample Output:

--------------------------------
results for http://www.google.com/

content size: 38.06 kb

http requests: 9
status 200: 6
status 204: 1
status 403: 2

profiler timing:
2.063 secs (page load)
2.047 secs (network: end last request)
0.111 secs (network: end first request)

file extensions: (count, size)
gif: 1, 8.558 kb
ico: 2, 2.488 kb
js: 2, 18.046 kb
png: 1, 5.401 kb
unknown: 3, 3.567 kb

http timing detail:
403, GET, /favicon.ico, 111 ms
200, GET, /newkey, 738 ms
200, GET, /, 332 ms
403, GET, /favicon.ico, 3 ms
200, GET, /logo.gif, 255 ms
200, GET, /d9n_Nh4I09g.js, 411 ms
200, GET, /2cca7b2e99206b9c.js, 65 ms
204, GET, /generate_204, 88 ms
200, GET, /nav_logo7.png, 49 ms