Wednesday, July 24, 2013

Closing ssh tunnel

ps aux | grep ssh
to get list of processes matching ssh
kill [proc id]
matching the tunneling

This frees up the port.

Friday, July 19, 2013

Bug in Tk Listbox

Run the script below. Clicking on the window will fire off <<ListboxSelect>> events even though the widget is disabled. Keyboard actions do not fire this event.

import Tkinter as tki

def selection_changed(event):
  print 'Selection changed'

root = tki.Tk()
listbox = tki.Listbox(root, selectmode=tki.BROWSE)
listbox.pack(side='left', fill='both', expand=True)
listbox.bind('<>', selection_changed)
listbox.config(state=tki.DISABLED)
root.mainloop()

Python bug ticket:  18506  (The python guys bounced me to the Tcl/Tk guys)
Tcl/Tk bug ticket: 67c8e8bd71

UPDATE: Is the same as a previously reported bug (1288433). Given that is has been open for 7 years, with a seemingly minor fix, it would appear that it won't be fixed any time soon. The work around is to check to see if the listbox is disabled before processing the event.

Friday, July 12, 2013

Run IPython notebook on remote server

This comes in very useful if you want to run your notebook on a remote machine (e.g. your data is on that machine, or the machine is a lot faster than your own). From hints here.
  1. Start ipython notebook on remote machine: ipython notebook --pylab inline --no-browser --port=7000 
  2. Setup tunneling on local machine: ssh -N -f -L localhost:7000:localhost:7000 login@the.remote.machine 
  3. Open up localhost:7000 on your browser

Thursday, July 11, 2013

Install latest Ipython

git clone https://github.com/ipython/ipython.git
cd ipython
python setup.py install --user
Don't forget to get rid of the other two or three installations of Ipython, as the case may be (It was three in my case). Also, don't forget to get latest dependencies

Python subprocess, Popen and PIPE

Typically when using Python's subprocess we use PIPEs to communicate with the process. However, it turns out, PIPEs suck when the data gets even slightly large (somewhere in the vicinity of 16K). You can verify this by running the following test code:
from subprocess import Popen, PIPE
import argparse, time

def execute(n):
  p = Popen(['python', 'test.py', '-n', str(n)], stdin=PIPE, stdout=PIPE, stderr=PIPE)
  p.wait()
  return p.stdout.read().splitlines()

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument('-n', type=int)
  args = parser.parse_args()
  if args.n is not None:
    print '0'*args.n
  else:
    for n in [10,100,1000,10000,12000,16000,16200, 16500]:
      t0 = time.clock()
      execute(n)
      print n, time.clock() - t0
The output is
10 0.001219
100 0.001254
1000 0.001162
10000 0.001362
12000 0.001429
16000 0.001305
16200 0.00121
(Hangs after this)
The way to handle this is to generate a temporary file and let the process write to the file. A detailed note can be found here.
def execute_long(n):
  with open('query.txt','w') as stdout:
    p = Popen(['python', 'test.py', '-n', str(n)], stdin=PIPE, stdout=stdout, stderr=PIPE)
    p.wait()
  with open('query.txt','r') as stdout:
    return stdout.read().splitlines()

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument('-n', type=int)
  args = parser.parse_args()
  if args.n is not None:
    print '0'*args.n
  else:
    for n in [10,100,1000,10000,12000,16000,16200, 16500]:
      t0 = time.clock()
      execute_long(n)
      print n, time.clock() - t0
10 0.001601
100 0.001263
1000 0.001272
10000 0.001404
12000 0.001419
16000 0.001333
32000 0.001445
64000 0.001692
128000 0.001763

Saturday, July 6, 2013

github gh-pages original markdown is stored in params.json

As you know github lets you put up webpages for your projects and these are stored in branch of your repository called 'gh-pages'.

Github also lets you write the page in Markdown and then converts it into html automatically. I am thrilled by this as you can also import your Readme.md file from your main project. I was also impressed by the fact that you can go back to the automatic page generator and reload the page as markdown and edit it. But I could not find the markdown source - all I saw was index.html and I wondered what magic github did to reverse convert html to markdown. This puzzled me because it did not look like a reversible operation.

Well, the secret is in the params.json file. The markdown, site title and tagline are in this file!

Friday, July 5, 2013

Mac OS X: make a screen cast with no additional software

I recently learned that on Mac OS X (> 10.6) it is possible to create decent screen casts using only the built in utilities (From hints here and here):

For the basic screen Quicktime is sufficient. Open up Quicktime and go to File->New Screen Recording. A small control panel will open that allows you to control recording. The small dropdown arrow on the right gives access to various recording options, including sound. When you are ready hit the record button. QT will tell you to click to start right away recording the whole screen, or drag your mouse and select a part of the screen to record from. Then you get a 'start' button which you should click to start recording. If you have activated voice recording you can see your voice level in the control panel.

If you want to visualize your keystrokes on the screen (and don't want to spend money on separate software that does this in a fancy way) you can do the following: Go to System Preferences->Keyboard. Check 'Show keyboard and character viewers in menu bar'. This shows a flag on your menu bar corresponding to the current language. Click the flag and check 'Show keyboard viewer'. This will show a schematic keyboard on your screen which lights up with the keys you press. There is no persistence, so it is not as apparent as specialized software made for screen casts.

Additionally, if you have a cluttered desktop, from a hint here, you can hide all the icons as follows: In a terminal type defaults write com.apple.finder CreateDesktop -bool false And then restart Finder. To unhide the icons type defaults write com.apple.finder CreateDesktop -bool true And then restart Finder

Monday, July 1, 2013

Stacking event bindings in tkinter

To stack events in Tkinter one should use the add='+' keyword (from here):
widget.bind("", callback1)
widget.bind("", callback2, add="+")
If you don't use the add='+' in the second call, then the first callback binding gets overwritten