<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;CkUFRH8-eyp7ImA9WhRbEkU.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008</id><updated>2012-02-03T06:43:35.153-08:00</updated><category term="pure" /><category term="twisted" /><category term="web" /><category term="registry" /><category term="api" /><category term="open source" /><category term="ttc" /><category term="pyside" /><category term="audio" /><category term="module" /><category term="hint" /><category term="css" /><category term="extension" /><category term="rss" /><category term="spam" /><category term="nosql" /><category term="eclipse" /><category term="vim" /><category term="hg" /><category term="wsh" /><category term="backup" /><category term="patch" /><category term="virtualbox" /><category term="unified" /><category term="java" /><category term="bzr" /><category term="security" /><category term="swig" /><category term="wacko" /><category term="msxml" /><category term="format" /><category term="diff" /><category term="django" /><category term="gui" /><category term="pdf" /><category term="batch" /><category term="c" /><category term="output" /><category term="trac" /><category term="build" /><category term="software" /><category term="atom" /><category term="ssl" /><category term="design" /><category term="network" /><category term="framework" /><category term="project" /><category term="automation" /><category term="zend" /><category term="vcs" /><category term="google" /><category term="svn" /><category term="whitespace" /><category term="wiki" /><category term="proxy" /><category term="timeline" /><category term="sphinx" /><category term="subprocess" /><category term="local network" /><category term="dump" /><category term="recover" /><category term="console" /><category term="mingw" /><category term="flow" /><category term="evaluation" /><category term="python" /><category term="plugin" /><category term="parsers" /><category term="debian" /><category term="script" /><category term="windows" /><category term="windows 2000" /><category term="port" /><category term="scons" /><category term="colorer" /><category term="update" /><category term="apache" /><category term="hack" /><category term="idea" /><category term="cvs" /><category term="py2exe" /><category term="php" /><category term="programming" /><category term="sqlite" /><category term="pysqlite" /><category term="interoperability" /><category term="xslt" /><category term="vnc" /><category term="tip" /><category term="trash" /><category term="jquery" /><category term="sus" /><category term="cgi" /><category term="appengine" /><category term="far manager" /><category term="languages" /><category term="chromium" /><category term="https" /><category term="gcc" /><category term="bootstrap" /><category term="mercurial" /><category term="management" /><category term="industrial" /><title>another day another vice another roll of the dice</title><subtitle type="html">solutions - hacks, diffs and patches</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>66</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/techtonik" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="techtonik" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A08DRXo9eCp7ImA9WhRSEU4.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-8092677205295578082</id><published>2011-11-12T14:09:00.001-08:00</published><updated>2011-11-12T15:17:54.460-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-12T15:17:54.460-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="vnc" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>Python based VNC client in browser</title><content type="html">What I really like in open source is when people reuse existing stuff to bring up something new. Today Arkaitz Jimenez brought up &lt;a href="http://arkaitzj.wordpress.com/2011/11/12/vnc-in-your-browser-through-websockets-handled-by-gevent/"&gt;a way to connect to VNC server with browser&lt;/a&gt; using&amp;nbsp;hybrid&amp;nbsp;solution from Python, JavaScript, gevent and WebSockets.&lt;br /&gt;
&lt;br /&gt;
The exciting thing that this project uses patched version of&amp;nbsp;&lt;a href="http://code.google.com/p/python-vnc-viewer/"&gt;python-vnc-viewer&lt;/a&gt;&amp;nbsp;written by Chris Liechti that I've&amp;nbsp;uploaded to Google Code, because it had to be updated&amp;nbsp;to work with modern versions of required libraries. It is nice to see this effort brought up something cool today.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-8092677205295578082?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/8092677205295578082/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/11/python-based-vnc-client-in-browser.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8092677205295578082?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8092677205295578082?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/11/python-based-vnc-client-in-browser.html" title="Python based VNC client in browser" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUABR3k-cSp7ImA9WhdXFUQ.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-7248412585026021307</id><published>2011-08-28T23:02:00.000-07:00</published><updated>2011-08-28T23:02:36.759-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-28T23:02:36.759-07:00</app:edited><title>How to make disk in memory in Linux</title><content type="html">&lt;br /&gt;
Disks in memory are useful for one major reason - speed. It is invaluable for test execution. While the idea is not new, there was no incentive to explore it until I've run upon &lt;a href="http://en.wikipedia.org/wiki/Tmpfs"&gt;tmpfs&lt;/a&gt;&amp;nbsp;reference in Ubuntu Wiki.&lt;br /&gt;
&lt;br /&gt;
For example, to get 2Gb of space for files in RAM, edit &lt;b&gt;/etc/fstab&lt;/b&gt;&amp;nbsp;to add the following line:&lt;br /&gt;
&lt;code class="prettyprint"&gt;&lt;pre&gt;
tmpfs &amp;nbsp; &amp;nbsp; /var/ramspace &amp;nbsp; &amp;nbsp; &amp;nbsp; tmpfs &amp;nbsp; &amp;nbsp; defaults,size=2048M &amp;nbsp; &amp;nbsp; 0 &amp;nbsp; &amp;nbsp; 0&lt;/pre&gt;&lt;/code&gt;
&lt;b&gt;/var/ramspace&lt;/b&gt; is now the place to store your files in memory.&lt;br /&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-7248412585026021307?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/7248412585026021307/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/08/how-to-make-disk-in-memory-in-linux.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/7248412585026021307?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/7248412585026021307?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/08/how-to-make-disk-in-memory-in-linux.html" title="How to make disk in memory in Linux" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CEcMRH4-eip7ImA9WhZaF00.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-701608418101240666</id><published>2011-07-03T07:08:00.000-07:00</published><updated>2011-07-03T07:08:05.052-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-03T07:08:05.052-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="output" /><category scheme="http://www.blogger.com/atom/ns#" term="pure" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="audio" /><title>Audio output on Windows with pure Python + ctypes</title><content type="html">I want to make a simple walkie-talkie for a local LAN to have fun with my friends. I've created&amp;nbsp;&lt;a href="http://code.google.com/p/rainforce/wiki/RawAudioSocket"&gt;Raw Audio Socket&lt;/a&gt;&amp;nbsp;spec to keep it really simple. We have a lot of different operating systems, so it would be nice to have a single implementation that can be run cross-platform. I chose Python and started with getting the sound playing on Windows.&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Python is known for its easy integration with C libraries and, indeed, there is a lot of Python bindings calling audio libraries written in C from Python. However, it requires the library to be compiled for your specific platform. I chose to avoid dependencies on any C code and instead call Windows WinMM Multimedia API &amp;nbsp;directly with &lt;a href="http://docs.python.org/2.7/library/ctypes.html"&gt;ctypes&lt;/a&gt;&amp;nbsp;module.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Thanks to an excellent tutorial by David Overton, here is the pure Python proof of concept that plays standard CD Audio PCM 44.1kHz&amp;nbsp;16bit Stereo sample from external file to the default sound device.&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;
"""
Implementation of Raw Audio Socket server spec in pure Python
http://code.google.com/p/rainforce/wiki/RawAudioSocket

"""

import sys

#-- CHAPTER 1: CONTINUOUS SOUND PLAYBACK WITH WINDOWS WINMM LIBRARY --
#
# Based on tutorial "Playing Audio in Windows using waveOut Interface"
# by David Overton

import ctypes
from ctypes import wintypes


# 1. Open Sound Device

# --- define necessary data structures from mmsystem.h
HWAVEOUT = wintypes.HANDLE
WAVE_FORMAT_PCM = 0x1
WAVE_MAPPER = -1
CALLBACK_NULL = 0
MMSYSERR_NOERROR = 0

class WAVEFORMATEX(ctypes.Structure):
  _fields_ = [
    ('wFormatTag',  wintypes.WORD),
      # 0x0001 WAVE_FORMAT_PCM. PCM audio
      # 0xFFFE The format is specified in the WAVEFORMATEXTENSIBLE.SubFormat
      # Other values are in mmreg.h 
    ('nChannels',   wintypes.WORD),
    ('SamplesPerSec',  wintypes.DWORD),
    ('AvgBytesPerSec', wintypes.DWORD),
      # for WAVE_FORMAT_PCM is the product of nSamplesPerSec and nBlockAlign
    ('nBlockAlign', wintypes.WORD),
      # for WAVE_FORMAT_PCM is the product of nChannels and wBitsPerSample
      # divided by 8 (bits per byte)
    ('wBitsPerSample', wintypes.WORD),
      # for WAVE_FORMAT_PCM should be equal to 8 or 16
    ('cbSize',      wintypes.WORD)]
      # extra format information size, should be 0
# --- /define

# Data must be processes in pieces that are multiple of
# nBlockAlign bytes of data at a time. Written and read
# data from a device must always start at the beginning
# of a block. Playback of PCM data can not be started in
# the middle of a sample on a non-block-aligned boundary.

hwaveout = HWAVEOUT()
wavefx = WAVEFORMATEX(
  WAVE_FORMAT_PCM,
  2,     # nChannels
  44100, # SamplesPerSec
  705600,# AvgBytesPerSec = 44100 SamplesPerSec * 16 wBitsPerSample
  4,     # nBlockAlign = 2 nChannels * 16 wBitsPerSample / 8 bits per byte
  16,    # wBitsPerSample
  0
)

# Open default wave device
ret = ctypes.windll.winmm.waveOutOpen(
  ctypes.byref(hwaveout), # buffer to receive a handle identifying
                          # the open waveform-audio output device
  WAVE_MAPPER,            # constant to point to default wave device
  ctypes.byref(wavefx),   # identifier for data format sent for device
  0, # DWORD_PTR dwCallback - callback mechanizm
  0, # DWORD_PTR dwCallbackInstance - user instance data for callback
  CALLBACK_NULL # DWORD fdwOpen - flag for opening the device
)

if ret != MMSYSERR_NOERROR:
  sys.exit('Error opening default waveform audio device (WAVE_MAPPER)')

print "Default Wave Audio output device is opened successfully"


# 2. Write Audio Blocks to Device

# --- define necessary data structures
PVOID = wintypes.HANDLE
WAVERR_BASE = 32
WAVERR_STILLPLAYING = WAVERR_BASE + 1
class WAVEHDR(ctypes.Structure):
  _fields_ = [
    ('lpData', wintypes.LPSTR), # pointer to waveform buffer
    ('dwBufferLength', wintypes.DWORD),  # in bytes
    ('dwBytesRecorded', wintypes.DWORD), # when used in input
    ('dwUser', wintypes.DWORD),          # user data
    ('dwFlags', wintypes.DWORD),
    ('dwLoops', wintypes.DWORD),  # times to loop, for output buffers only
    ('lpNext', PVOID),            # reserved, struct wavehdr_tag *lpNext
    ('reserved', wintypes.DWORD)] # reserved
# The lpData, dwBufferLength, and dwFlags members must be set before calling
# the waveInPrepareHeader or waveOutPrepareHeader function. (For either
# function, the dwFlags member must be set to zero.)
# --- /define

class AudioWriter(object):
  def __init__(self, hwaveout):
    self.hwaveout = hwaveout
    self.wavehdr = WAVEHDR()

  def write(self, data):
    self.wavehdr.dwBufferLength = len(data)
    self.wavehdr.lpData = data
    
    # Prepare block for playback
    if ctypes.windll.winmm.waveOutPrepareHeader(
         self.hwaveout, ctypes.byref(self.wavehdr), ctypes.sizeof(self.wavehdr)
       ) != MMSYSERR_NOERROR:
      sys.exit('Error: waveOutPrepareHeader failed')

    # Write block, returns immediately unless a synchronous driver is
    # used (not often)
    if ctypes.windll.winmm.waveOutWrite(
         self.hwaveout, ctypes.byref(self.wavehdr), ctypes.sizeof(self.wavehdr)
       ) != MMSYSERR_NOERROR:
      sys.exit('Error: waveOutWrite failed')

    # [ ] calculate sleep delay based on sample length
    # iii [ ] Measure CPU usage spike during wait without delay
    import time
    time.sleep(1)

    # Wait until playback is finished
    while True:
      # unpreparing the header fails until the block is played
      ret = ctypes.windll.winmm.waveOutUnprepareHeader(
              self.hwaveout,
              ctypes.byref(self.wavehdr),
              ctypes.sizeof(self.wavehdr)
            )
      if ret == WAVERR_STILLPLAYING:
        import time
        time.sleep(1)
        continue
      if ret != MMSYSERR_NOERROR:
        sys.exit('Error: waveOutUnprepareHeader failed with code 0x%x' % ret)
      break


# [ ] it's no good to read all the PCM data into memory at once
data = open('95672__Corsica_S__frequency_change_approved.raw', 'rb').read()

aw = AudioWriter(hwaveout)
aw.write(data)


# x. Close Sound Device

ctypes.windll.winmm.waveOutClose(hwaveout)
print "Default Wave Audio output device is closed"

#-- /CHAPTER 1 --
&lt;/code&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Windows also provides DirectSound API, but it looks too complicated for me ATM. The code above is also available from &lt;a href="https://bitbucket.org/techtonik/audiosocket"&gt;https://bitbucket.org/techtonik/audiosocket&lt;/a&gt; and marked with 0.1 tag. You may expect to find further modifications there.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-701608418101240666?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/701608418101240666/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/07/audio-output-on-windows-with-pure.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/701608418101240666?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/701608418101240666?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/07/audio-output-on-windows-with-pure.html" title="Audio output on Windows with pure Python + ctypes" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CE4GRHw4eSp7ImA9WhZWGE8.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-1897553707382843613</id><published>2011-05-19T09:25:00.000-07:00</published><updated>2011-05-19T09:35:25.231-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-19T09:35:25.231-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vcs" /><category scheme="http://www.blogger.com/atom/ns#" term="svn" /><title>Why Subversion conflict resolution suxx?</title><content type="html">Because conflict resolution choice is confusing (for non-English natives for sure):&lt;br /&gt;
&lt;pre&gt;&lt;code class="prettyprint"
&gt;$ svn up
U &amp;nbsp; &amp;nbsp;bitten\slave.py
G &amp;nbsp; &amp;nbsp;bitten\tests\queue.py
Conflict discovered in 'bitten/queue.py'.
Select: (p) postpone, (df) diff-full, (e) edit,
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (mc) mine-conflict, (tc) theirs-conflict,
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (s) show all options:&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;
Should you&amp;nbsp;select&amp;nbsp;"theirs conflict" or "mine confict" to fix your code? In situation when you feel that incoming change is right you may want to select "mine conflict" as the change that conflicts and should be removed as a result. But the correct answer it to select "theirs conflict" as the change to be incorporated in your code. Subversion developers think that you're are not removing conflicts, but incorporating them into your code. If they could think of user action - it is &lt;b&gt;removing &lt;/b&gt;or &lt;b&gt;resolving conflict&lt;/b&gt;&amp;nbsp;in high-level terminology, or &lt;b&gt;selecting correct change&lt;/b&gt;&amp;nbsp;in&amp;nbsp;low-level description.&lt;br /&gt;
&lt;br /&gt;
Let's see the help:&lt;br /&gt;
&lt;pre&gt;&lt;code class="prettyprint"
&gt;Conflict discovered in 'bitten/slave.py'.
Select: (p) postpone, (df) diff-full, (e) edit,
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (mc) mine-conflict, (tc) theirs-conflict,
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (s) show all options: s
&amp;nbsp; (e) &amp;nbsp;edit &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - change merged file in an editor
&amp;nbsp; (df) diff-full &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- show all changes made to merged file
&amp;nbsp; (r) &amp;nbsp;resolved &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - accept merged version of file
&amp;nbsp; (dc) display-conflict - show all conflicts (ignoring merged version)
&amp;nbsp; (mc) mine-conflict &amp;nbsp; &amp;nbsp;- accept my version for all conflicts (same)
&amp;nbsp; (tc) theirs-conflict &amp;nbsp;- accept their version for all conflicts (same)
&amp;nbsp; (mf) mine-full &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- accept my version of entire file (even non-conflicts)
&amp;nbsp; (tf) theirs-full &amp;nbsp; &amp;nbsp; &amp;nbsp;- accept their version of entire file (same)
&amp;nbsp; (p) &amp;nbsp;postpone &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - mark the conflict to be resolved later
&amp;nbsp; (l) &amp;nbsp;launch &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - launch external tool to resolve conflict
&amp;nbsp; (s) &amp;nbsp;show all &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - show this list&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Frankly, I can't understand how &lt;b&gt;(mc)&lt;/b&gt; is different from &lt;b&gt;(mf)&lt;/b&gt; if both versions accept all changes. &lt;b&gt;(same)&lt;/b&gt; marker doesn't add much sense either. But even if help doesn't describe anything - these options were still added for a reason, and if we meditate a bit on them starting from the bottom comment to &lt;b&gt;(mf)&lt;/b&gt; help, it becomes clear that:&lt;br /&gt;
&lt;br /&gt;
1. &lt;b&gt;(mf)&lt;/b&gt; throws away any incoming changes for the given file even if some of them were merged successfully&lt;br /&gt;
2. that means &lt;b&gt;(mc)&lt;/b&gt; probably keeps the changes that were merged successfully&lt;br /&gt;
3. that means &lt;b&gt;(df)&lt;/b&gt; shows more changes than &lt;b&gt;(dc)&lt;/b&gt; output&lt;br /&gt;
&lt;br /&gt;
Recommendations? Introduce `&lt;b&gt;change&lt;/b&gt;` and `&lt;b&gt;conflict&lt;/b&gt;` terminology earlier, i.e. show info like `3 changes, 2 conflicts`. It will also allow incremental conflict resolution, like if you &lt;b&gt;(e)&lt;/b&gt;dited the counter is changed to `4 changes, 1 conflict` etc. Final recommendation if to replace `(ignoring merged version)` with `(ignoring merged changes)` string. There are surely more ways to improve this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-1897553707382843613?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/1897553707382843613/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/05/why-subversion-conflict-resolution-suxx.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1897553707382843613?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1897553707382843613?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/05/why-subversion-conflict-resolution-suxx.html" title="Why Subversion conflict resolution suxx?" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEIMQHw8eip7ImA9WhZXEEQ.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-7330819542248134898</id><published>2011-04-29T10:03:00.000-07:00</published><updated>2011-04-29T10:03:01.272-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-29T10:03:01.272-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="chromium" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><title>Chrome logo was awesome</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;This is a Chrome 11 logo.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-I7lP6bMbbsI/TbruzHgVtTI/AAAAAAAAAZY/iNfNuNuvqMk/s1600/new_chrome_logo_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="181" src="http://2.bp.blogspot.com/-I7lP6bMbbsI/TbruzHgVtTI/AAAAAAAAAZY/iNfNuNuvqMk/s320/new_chrome_logo_11.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: center;"&gt;This one is the old variant.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-LDaHoRmXnwg/TbrvAYebu3I/AAAAAAAAAZc/Gj211UFgShc/s1600/old_chrome_logo_is_awesome.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="178" src="http://2.bp.blogspot.com/-LDaHoRmXnwg/TbrvAYebu3I/AAAAAAAAAZc/Gj211UFgShc/s320/old_chrome_logo_is_awesome.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-7330819542248134898?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/7330819542248134898/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/04/chrome-logo-was-awesome.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/7330819542248134898?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/7330819542248134898?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/04/chrome-logo-was-awesome.html" title="Chrome logo was awesome" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-I7lP6bMbbsI/TbruzHgVtTI/AAAAAAAAAZY/iNfNuNuvqMk/s72-c/new_chrome_logo_11.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0cCQnkzeCp7ImA9WhZREUg.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-9161931139797217770</id><published>2011-04-06T21:37:00.000-07:00</published><updated>2011-04-06T21:37:43.780-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-06T21:37:43.780-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="scons" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Finding unused files in a SCons project with Process Monitor</title><content type="html">New technologies are born and die, but one things remains in your project - their files. Quite often you have no idea about where are they used, and attempt to remove them may lead to serious consequences.&lt;br /&gt;
&lt;br /&gt;
Fortunately, if your project is managed by fine grained build system such as &lt;a href="http://www.scons.org/"&gt;SCons&lt;/a&gt;, if your build scripts are not &lt;a href="http://en.wikipedia.org/wiki/Glob_(programming)"&gt;globbing&lt;/a&gt; too much, there are chances you can find files that are not participating in the builds.&lt;br /&gt;
&lt;br /&gt;
Here is how to do this on Windows using &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896653"&gt;Process Monitor&lt;/a&gt; tool that intercepts all system calls including file access.&lt;br /&gt;
&lt;br /&gt;
While build systems are usually common for C/C++ and Java projects, it is possible to add fine-grained file usage control for any project. For example, SCons itself is written entirely in Python, it could run directly from the source checkout or build distributives from checkout. But instead, it uses build procedure to copy all necessary files from checkout into separate directory and do stuff from there.&lt;br /&gt;
&lt;br /&gt;
Thanks to that it is possible to see which files are no more actual. While it is possible to compare checkout source tree and copied directory trees, I'll go through the hells of monitoring system file access in a source tree during the build process using Process Monitor (FileMon in the past). Linux should have similar tools too - let me know how are they called.&lt;br /&gt;
&lt;br /&gt;
The process is the following:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Start Process Monitor&lt;/li&gt;
&lt;li&gt;Stop incoming event flood by (un)clicking Capture (Ctrl-E) button&lt;/li&gt;
&lt;li&gt;Open Filter (Ctrl-L) dialog to add some filters&lt;/li&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-h9OvBkQwtSs/TZ029cop9OI/AAAAAAAAAZM/H1fRSJ-C0ik/s1600/process_monitor_filter.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="195" width="400" src="http://2.bp.blogspot.com/-h9OvBkQwtSs/TZ029cop9OI/AAAAAAAAAZM/H1fRSJ-C0ik/s400/process_monitor_filter.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;SCons build is started by &lt;code&gt;bootstrap.py&lt;/code&gt; script from a root of SCons source checkout. The script is executed by python executable, so I add &lt;code&gt;python.exe&lt;/code&gt; process name to the filter. I know that &lt;code&gt;bootstrap.py&lt;/code&gt; copies files from &lt;code&gt;src/&lt;/code&gt; subdirectory, so it is the directory I need to monitor, so I add this dir to filters too.&lt;/p&gt;

&lt;li&gt;Go Tools -&gt; File Summary...&lt;/li&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8x-iINT66iw/TZ010TFqkFI/AAAAAAAAAZE/JgnwuUuR_h0/s1600/process_monitor_file_summary.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="382" width="400" src="http://3.bp.blogspot.com/-8x-iINT66iw/TZ010TFqkFI/AAAAAAAAAZE/JgnwuUuR_h0/s400/process_monitor_file_summary.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There is a list of paths catched by Process Monitor when listening to system calls. They are already filtered, but additional filters can be applied using bottom left button to make information even more useful.&lt;/p&gt;

&lt;li&gt;Export to CSV using Save...&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
Exported CSV is not very useful without some postprocessing. I used the following a script to compare the list of paths in CSV to actual &lt;code&gt;src/&lt;/code&gt; directory contents. This gives me names of files that were not touched during build at all.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code class="prettyprint"&gt;SRCDIR = "C:\\p\\python\\scons\\src"
CSVLIST = 'accessed_bootstrap_files.CSV'

import csv
import os

reader = csv.reader(open(CSVLIST))
header = reader.next()
pathidx = header.index("Path")
pathset = set([row[pathidx] for row in reader])

#for row in pathset:
#  print row

fileset = set()
for root, dirs, files in os.walk(SRCDIR):
  fileset.update( [os.path.join(root, f) for f in files] )
  if '.svn' in dirs:
    dirs.remove('.svn')  # don't visit .svn directories

if len(pathset &amp;amp; fileset) == 0:
  print 'Error: File sets do not intersect at all'

print "Files not found in source directory tree:"
for f in (pathset - fileset):
  if not os.path.isdir(f):
    print f

print
print "Untouched files in source directory tree:"
for f in sorted(fileset - pathset):
  if not os.path.isdir(f):
    print f
&lt;/code&gt;&lt;/pre&gt;I've found a few interesting things about SCons. Core tests are mixed with source files in repository checkout. They are not copied during bootstrap build. There are also few &lt;code&gt;setup.py&lt;/code&gt; files, post-install script and announcement that don't participate in the build.&lt;br /&gt;
&lt;br /&gt;
Here is the output of the above script:&lt;br /&gt;
&lt;code class="prettyprint"&gt;&lt;br /&gt;
Files not found in source directory tree:&lt;br /&gt;
&amp;lt;Total&gt;&lt;br /&gt;
&lt;br /&gt;
Untouched files in source directory tree:&lt;br /&gt;
C:\p\python\scons\src\.aeignore&lt;br /&gt;
C:\p\python\scons\src\Announce.txt&lt;br /&gt;
C:\p\python\scons\src\engine\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\ActionTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\BuilderTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\CacheDirTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\DefaultsTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\EnvironmentTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\ErrorsTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\ExecutorTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\JobTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\MemoizeTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Node\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Node\AliasTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Node\FSTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Node\NodeTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Node\PythonTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Optik\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\PathListTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Platform\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Platform\PlatformTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\SConfTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\SConsignTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\CTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\DirTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\FortranTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\IDLTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\LaTeXTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\ProgTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\RCTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Scanner\ScannerTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Script\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Script\MainTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Script\SConscriptTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\SubstTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\TaskmasterTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Tool\.aeignore&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Tool\JavaCommonTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Tool\PharLapCommonTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Tool\ToolTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Tool\f03.xml&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Tool\msvsTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\UtilTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Variables\BoolVariableTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Variables\EnumVariableTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Variables\ListVariableTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Variables\PackageVariableTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Variables\PathVariableTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\Variables\VariablesTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\WarningsTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\SCons\cppTests.py&lt;br /&gt;
C:\p\python\scons\src\engine\setup.cfg&lt;br /&gt;
C:\p\python\scons\src\engine\setup.py&lt;br /&gt;
C:\p\python\scons\src\script\.aeignore&lt;br /&gt;
C:\p\python\scons\src\script\scons-post-install.py&lt;br /&gt;
C:\p\python\scons\src\script\setup.cfg&lt;br /&gt;
C:\p\python\scons\src\script\setup.py&lt;br /&gt;
C:\p\python\scons\src\test_aegistests.py&lt;br /&gt;
C:\p\python\scons\src\test_files.py&lt;br /&gt;
C:\p\python\scons\src\test_interrupts.py&lt;br /&gt;
C:\p\python\scons\src\test_pychecker.py&lt;br /&gt;
C:\p\python\scons\src\test_setup.py&lt;br /&gt;
C:\p\python\scons\src\test_strings.py&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Hope this helps clean up your projects too.&lt;br /&gt;
&lt;br /&gt;
P.S. I wish there was a Python script replacement for Process Monitor, or at least that it could be controlled from command line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-9161931139797217770?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/9161931139797217770/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/04/finding-unused-files-in-scons-project.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/9161931139797217770?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/9161931139797217770?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/04/finding-unused-files-in-scons-project.html" title="Finding unused files in a SCons project with Process Monitor" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-h9OvBkQwtSs/TZ029cop9OI/AAAAAAAAAZM/H1fRSJ-C0ik/s72-c/process_monitor_filter.png" height="72" width="72" /><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;CUEMQHY-eCp7ImA9WhZSF0s.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-1399030920720425777</id><published>2011-03-29T06:03:00.000-07:00</published><updated>2011-04-02T10:01:21.850-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-02T10:01:21.850-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="twisted" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Asynchronous input from Windows console</title><content type="html">&lt;b&gt;too long didn't read&lt;/b&gt; - &lt;a href="https://bitbucket.org/techtonik/async-console-input"&gt;https://bitbucket.org/techtonik/async-console-input&lt;/a&gt; - public domain/MIT example for Windows implemented in pure Python (ctypes)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What is asynchronous input?&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;Given:&lt;/b&gt; The program need to terminate immediately when a subprocess exits or user hits 'q'. It should not eat 100% CPU time.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Blocking synchronous input:&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="prettyprint"&gt;import sys, subprocess&lt;br /&gt;from msvcrt import getch, kbhit&lt;br /&gt;&lt;br /&gt;p = subprocess.Popen([r"notepad"], shell=True)&lt;br /&gt;&lt;br /&gt;while True:&lt;br /&gt;  char = getch()&lt;br /&gt;  if char == 'q':&lt;br /&gt;    sys.exit('terminated by user')&lt;br /&gt;  if p.poll() != None:&lt;br /&gt;    sys.exit('terminated by child exit')&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This one doesn't work (doesn't exits immediately when child process terminates), because getch() blocks execution key is pressed, and even if child process exits, it won't be detected until some key is pressed.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Non-blocking synchronous input (polling):&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;import sys, subprocess&lt;br /&gt;from msvcrt import getch, kbhit&lt;br /&gt;&lt;br /&gt;p = subprocess.Popen([r"notepad"], shell=True)&lt;br /&gt;&lt;br /&gt;while True:&lt;br /&gt;  while kbhit():&lt;br /&gt;    if getch() == 'q':&lt;br /&gt;      sys.exit('terminated by user')&lt;br /&gt;  if p.poll() != None:&lt;br /&gt;    sys.exit('terminated by child exit')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This works ok, but constant polling uses 100% of CPU resources.  It is possible to insert &lt;code&gt;time.sleep()&lt;/code&gt; instructions to reduce the carbon footprint, but these crutches will greatly slow down the console when you add &lt;a href="http://www.phoboslab.org/ztype/"&gt;z-type&lt;/a&gt; to console to spend your time until the background process is finished.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Asynchronous console input on Windows with Python&lt;/h3&gt;&lt;br /&gt;Asynchronous input allows your program to receive notification from operating system when an input is available. This means that you define events your program needs to &lt;b&gt;react&lt;/b&gt; (not necessary console events), send this list to operating system and put your program into &lt;code&gt;wait&lt;/code&gt; mode. When system sees this event, your wait function returns and it's possible to inspect/filter event to a greater detail.&lt;br /&gt;&lt;br /&gt;Windows provides &lt;b&gt;WaitForMultipleObjects&lt;/b&gt; wait function, and in Linux I believe it is &lt;b&gt;select&lt;/b&gt; call.  If you've tried to understand how &lt;a href="http://twistedmatrix.com/trac/"&gt;Twisted&lt;/a&gt; works, but couldn't - will it make more clear if I say that &lt;b&gt;twisted reactor&lt;/b&gt; is a &lt;b&gt;wait function&lt;/b&gt;? What you do when you code with twisted is just configuring events to react, making chains of them so that one event reacts to another event. This allow to build very interesting, complex and de-coupled asynchronous applications in a couple of days.&lt;br /&gt; &lt;br /&gt;O.k. Getting back from Twisted to the asynchronous console input on Windows. Below is the full source code that uses &lt;b&gt;WaitForMultipleObjects&lt;/b&gt;. I am afraid that's minimal complete example  possible to build with ctypes using Windows API. Tested with Python 2.5&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Non-blocking asynchronous input from console:&lt;/b&gt;&lt;br /&gt;&lt;a href="https://bitbucket.org/techtonik/async-console-input"&gt;https://bitbucket.org/techtonik/async-console-input&lt;/a&gt;&lt;pre class="prettyprint"&gt;"""&lt;br /&gt;Example of non-blocking asynchronous console input using&lt;br /&gt;Windows API calls in Python.  This can become handy for&lt;br /&gt;async console tools such as IRC client.&lt;br /&gt;&lt;br /&gt;Public domain or MIT license&lt;br /&gt;by anatoly techtonik &lt;techtonik@gmail.com&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Notes:&lt;br /&gt;  1. WaitForMultipleObjects is used to listen for the&lt;br /&gt;     signals from process and stdin handles&lt;br /&gt;  2. When handle is signalled it remains in this state&lt;br /&gt;     until reset&lt;br /&gt;  3. msvcrt.* keyboard functions don't clear signalled&lt;br /&gt;     state from stdin handle, that's why console API&lt;br /&gt;     functions are used to clear the input buffer&lt;br /&gt;     instead of kbhit()/getch() loop&lt;br /&gt;"""&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;import ctypes&lt;br /&gt;import ctypes.wintypes&lt;br /&gt;import subprocess&lt;br /&gt;&lt;br /&gt;# open notepad in separate process and monitor its execution&lt;br /&gt;# at the same time asynchronously processing events from&lt;br /&gt;# standard input without wasting 100% CPU on looping&lt;br /&gt;&lt;br /&gt;# OpenProcess desired access flag&lt;br /&gt;#   "the right to use the object for synchronization. This&lt;br /&gt;#    enables a thread to wait until the object is in the&lt;br /&gt;#    signaled state"&lt;br /&gt;SYNCHRONIZE=0x00100000L&lt;br /&gt;# Constant to get stdin handle with GetStdHandle() call&lt;br /&gt;STD_INPUT_HANDLE = -10&lt;br /&gt;# Constant for infinite timeout in WaitForMultipleObjects()&lt;br /&gt;INFINITE = -1&lt;br /&gt;&lt;br /&gt;# --- processing input structures -------------------------&lt;br /&gt;# INPUT_RECORD structure&lt;br /&gt;#  events:&lt;br /&gt;EVENTIDS = dict(&lt;br /&gt;  FOCUS_EVENT = 0x0010,&lt;br /&gt;  KEY_EVENT = 0x0001,      # only key event is handled&lt;br /&gt;  MENU_EVENT = 0x0008,&lt;br /&gt;  MOUSE_EVENT = 0x0002,&lt;br /&gt;  WINDOW_BUFFER_SIZE_EVENT = 0x0004)&lt;br /&gt;EVENTS = dict(zip(EVENTIDS.values(), EVENTIDS.keys()))&lt;br /&gt;#  records:&lt;br /&gt;class _uChar(ctypes.Union):&lt;br /&gt;  _fields_ = [('UnicodeChar', ctypes.wintypes.WCHAR),&lt;br /&gt;              ('AsciiChar', ctypes.wintypes.c_char)]&lt;br /&gt;class KEY_EVENT_RECORD(ctypes.Structure):&lt;br /&gt;  _fields_ = [&lt;br /&gt;    ('keyDown', ctypes.wintypes.BOOL),&lt;br /&gt;    ('repeatCount', ctypes.wintypes.WORD),&lt;br /&gt;    ('virtualKeyCode', ctypes.wintypes.WORD),&lt;br /&gt;    ('virtualScanCode', ctypes.wintypes.WORD),&lt;br /&gt;    ('char', _uChar),&lt;br /&gt;    ('controlKeyState', ctypes.wintypes.DWORD)]&lt;br /&gt;class _Event(ctypes.Union):&lt;br /&gt;  _fields_ = [('keyEvent', KEY_EVENT_RECORD)]&lt;br /&gt;  #  MOUSE_EVENT_RECORD        MouseEvent;&lt;br /&gt;  #  WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;&lt;br /&gt;  #  MENU_EVENT_RECORD         MenuEvent;&lt;br /&gt;  #  FOCUS_EVENT_RECORD        FocusEvent;&lt;br /&gt;class INPUT_RECORD(ctypes.Structure):&lt;br /&gt;  _fields_ = [&lt;br /&gt;    ('eventType', ctypes.wintypes.WORD),&lt;br /&gt;    ('event', _Event)]&lt;br /&gt;# --- /processing input structures ------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;np = subprocess.Popen([r"notepad"],&lt;br /&gt;       stdin=subprocess.PIPE,&lt;br /&gt;       stdout=subprocess.PIPE,&lt;br /&gt;       stderr=subprocess.PIPE,&lt;br /&gt;       shell=True)&lt;br /&gt;# OpenProcess returns handle that can be used in wait functions&lt;br /&gt;# params: desiredAccess, inheritHandle, processId&lt;br /&gt;nph = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, np.pid)&lt;br /&gt;print("Started Notepad with pid=%s, handle=%s" % (np.pid, nph))&lt;br /&gt;&lt;br /&gt;ch = ctypes.windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)&lt;br /&gt;&lt;br /&gt;handles = [ch, nph]&lt;br /&gt;&lt;br /&gt;ctypes.windll.kernel32.FlushConsoleInputBuffer(ch)&lt;br /&gt;eventnum = ctypes.wintypes.DWORD()&lt;br /&gt;eventread = ctypes.wintypes.DWORD()&lt;br /&gt;inbuf = (INPUT_RECORD * 1)()&lt;br /&gt;&lt;br /&gt;print "[q]uit, [s]top console processing, launch bro[w]ser"&lt;br /&gt;stopflag = False&lt;br /&gt;while not stopflag and nph in handles:&lt;br /&gt;    print "Waiting for handles %s.." % handles&lt;br /&gt;&lt;br /&gt;    HandleArrayType = ctypes.wintypes.HANDLE * len(handles)&lt;br /&gt;    handle_array = HandleArrayType(*handles)&lt;br /&gt;    # params: count, handles, waitAll, milliseconds&lt;br /&gt;    ret = ctypes.windll.kernel32.WaitForMultipleObjects(&lt;br /&gt;            len(handle_array), handle_array, False, INFINITE)&lt;br /&gt;&lt;br /&gt;    if handles[ret] == ch:&lt;br /&gt;        """&lt;br /&gt;        # msvcrt won't work, because it doesn't reset&lt;br /&gt;        # signalled state of stdin handle&lt;br /&gt;        import msvcrt&lt;br /&gt;        while msvcrt.kbhit():&lt;br /&gt;            print "key!"&lt;br /&gt;            print msvcrt.getch()&lt;br /&gt;        continue&lt;br /&gt;        """&lt;br /&gt;        # --- processing input ---------------------------&lt;br /&gt;        ctypes.windll.kernel32.GetNumberOfConsoleInputEvents(&lt;br /&gt;          ch, ctypes.byref(eventnum))&lt;br /&gt;        for i in range(eventnum.value):&lt;br /&gt;          # params: handler, buffer, length, eventsnum&lt;br /&gt;          ctypes.windll.kernel32.ReadConsoleInputW(&lt;br /&gt;            ch, ctypes.byref(inbuf), 2, ctypes.byref(eventread))&lt;br /&gt;          if EVENTS[inbuf[0].eventType] != 'KEY_EVENT':&lt;br /&gt;            print EVENTS[inbuf[0].eventType]&lt;br /&gt;            pass&lt;br /&gt;          else:&lt;br /&gt;            keyEvent = inbuf[0].event.keyEvent&lt;br /&gt;            if not keyEvent.keyDown:&lt;br /&gt;              continue&lt;br /&gt;            char = keyEvent.char.UnicodeChar.lower()&lt;br /&gt;            #print char, keyEvent&lt;br /&gt;            if char == 'q':&lt;br /&gt;              print('[q] key pressed. Exiting..')&lt;br /&gt;              stopflag = True&lt;br /&gt;            elif char == 's':&lt;br /&gt;              handles.remove(ch)&lt;br /&gt;            elif char == 'w':&lt;br /&gt;              import webbrowser&lt;br /&gt;              webbrowser.open('http://techtonik.rainforce.org')&lt;br /&gt;            #print char&lt;br /&gt;        # --- /processing input --------------------------&lt;br /&gt;&lt;br /&gt;    elif handles[ret] == nph:&lt;br /&gt;        print("Notepad is closed. Exiting..")&lt;br /&gt;        handles.remove(nph)&lt;br /&gt;    else:&lt;br /&gt;        print("Warning: Unknown return value '%s'" % ret)&lt;br /&gt;&lt;br /&gt;ctypes.windll.kernel32.FlushConsoleInputBuffer(ch)&lt;br /&gt;ctypes.windll.kernel32.CloseHandle(nph)&lt;br /&gt;print "Done."&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Where can it be useful?&lt;/h3&gt;&lt;br /&gt;Writing first Windows console IRC client in Python and make it cross-platform? Network log viewers with keyboard shortcuts? Real-time roguelikes? Matrix sniffer screensaver? I don't know - its your time. Hope I saved you some though.&lt;br /&gt;&lt;br /&gt;Enjoy! If you want to enhance this stuff - feel free to join ever empty &lt;a href="https://groups.google.com/forum/#!forum/rainforce"&gt;https://groups.google.com/forum/#!forum/rainforce&lt;/a&gt; for public discussion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-1399030920720425777?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/1399030920720425777/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/03/asynchronous-input-from-windows-console.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1399030920720425777?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1399030920720425777?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/03/asynchronous-input-from-windows-console.html" title="Asynchronous input from Windows console" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DkQCQHw4eCp7ImA9WhZTGE0.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-6417076885534119284</id><published>2011-03-22T07:24:00.000-07:00</published><updated>2011-03-22T07:32:41.230-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-22T07:32:41.230-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="evaluation" /><category scheme="http://www.blogger.com/atom/ns#" term="api" /><category scheme="http://www.blogger.com/atom/ns#" term="idea" /><category scheme="http://www.blogger.com/atom/ns#" term="django" /><category scheme="http://www.blogger.com/atom/ns#" term="framework" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="design" /><category scheme="http://www.blogger.com/atom/ns#" term="flow" /><category scheme="http://www.blogger.com/atom/ns#" term="appengine" /><title>User Pattern: Button Status</title><content type="html">&lt;h4&gt;Introduction into User Patterns&lt;/h4&gt;&lt;br /&gt;
Many of you know about &lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Design_pattern_(computer_science)"&gt;Design Patterns&lt;/a&gt;&lt;/b&gt; of software development, invented to make complicated solutions look less complicated. The problem with Design Patterns is that they describe solutions to coding problems - not for user problem. People abusing Design Patterns tend to align the functionality of application to patterns, sacrificing features users wanted. The application that looks well-designed in the eyes of developers, in fact makes even simple features hard to implement or just takes too much time. As time passes, users become dissatisfied and eventually lose all interest in the product.&lt;br /&gt;
&lt;br /&gt;
People tried to approach the problem from the other end with &lt;b&gt;User Interface Design&lt;/b&gt; guidelines. This often made developers unhappy, because their Design Patterns don't explain how to work with web and Ajax application where "business logic" becomes shared between client and server. Developers wanted to see how different frameworks approach this stuff and to make the development process more intuitive. For this reason there should be a way to see how some typical features/functionality are implemented in different frameworks and this should be more detailed than a wiki or a blog in 15 minutes.&lt;br /&gt;
&lt;br /&gt;
So, let me introduce &lt;b&gt;User Patterns&lt;/b&gt;. User Pattern is a very abstract story, missing details about design decisions, but detailed enough to provide implementation and see &lt;b&gt;how _simple_, _extensible_ and _maintainable_&lt;/b&gt; this implementation is.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;Button Status User Pattern&lt;/h4&gt;&lt;br /&gt;
&lt;b&gt;User story: &lt;/b&gt;I want a page with a button and a status field displayed. When I click the button, the status should be updated.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Description: &lt;/b&gt;There are five levels in the quest for the implementation of this pattern.&lt;br /&gt;
Level 1. The status is blank - it is fetched/calculated only when the button is pressed.&lt;br /&gt;
Level 2. The status is initially available - and it is refreshed/calculated when the button is pressed.&lt;br /&gt;
Level 3. When refresh/recalculation fails, the error value is displayed in status field.&lt;br /&gt;
Level 4. When refresh/recalculation fails, the error value is displayed in status field along with user friendly message in separate field&lt;br /&gt;
Level 5. The status value is stored in application database - when the button is pressed, it is recalculated, saved and only when displayed to the user&lt;br /&gt;
Level 6. When recalculation/save or fetch operation fails, user should be presented with friendly message explaining the error and further action (i.e. report problem link)&lt;br /&gt;
&lt;br /&gt;
I'm looking forward to create samples for AppEngine webapp, classic Django and Django-nonrel. Feel free to share your snippets.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-6417076885534119284?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/6417076885534119284/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/03/user-pattern-button-status.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6417076885534119284?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6417076885534119284?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/03/user-pattern-button-status.html" title="User Pattern: Button Status" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUYFRn85fip7ImA9Wx9WFkk.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-588728865863622527</id><published>2011-01-21T13:57:00.000-08:00</published><updated>2011-01-21T13:58:37.126-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-21T13:58:37.126-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pyside" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>[PySide] Python for Qt version 1.0.0~beta4 "I have altered the deal" released</title><content type="html">I can't see this post on &lt;a href="http://planet.python.org"&gt;planet.python.org&lt;/a&gt; and can't resist to share the good news about new &lt;a href="http://www.pyside.org/"&gt;PySide&lt;/a&gt; release.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;The PySide team is happy to announce the fourth beta release of PySide:
Python for Qt. New versions of some of the PySide toolchain components
apiextractor, generatorrunner, shiboken, libpyside, pyside-tools have been
released as well.

Like the others, this is a source code release only; we hope our community
packagers will be providing provide binary packages shortly. To acquire the
source code packages, refer to our download wiki page [1] or pull the relevant
tagged versions from our git repositories [2].

Major changes since 1.0.0~beta3
===============================

This is a bug fix release. Since beta3, a total of 47 high-priority
bugs have been fixed. See the list of fixed bugs at the end of this message.

Path towards 1.0 release
========================

There are still some outstanding bugs in our Bugzilla [3]. To have these
fixed, we plan to do other beta in two weeks. The beta cycle will continue
until we have all P2 bugs fixed.


About PySide
============

PySide is the Nokia-sponsored Python Qt bindings project, providing
access to not only the complete Qt 4.7 framework but also Qt Mobility,
as well as to generator tools for rapidly generating bindings for any
Qt-based libraries.

The PySide project is developed in the open, with all facilities you'd
expect from any modern OSS project such as all code in a git repository
[2], an open Bugzilla [5] for reporting bugs, and an open design
process [4]. We welcome any contribution without requiring a transfer of
copyright.

List of bugs fixed
==================

624     button click emit doesn't work
484     Error compiling QtContacts 1.1 (problems with const QList&lt;qvariant&gt;)
498     powerStateChanged-SIGNAL not emitted!
509     Can't use Shiboken when both Debug and Released are installed.
528     Connecting to SIGNAL positionUpdated fails
552     Segmentation fault when using QUiLoader and QTabWidget
553     A warning against using QUILoader is needed in the documentation
560     Lack of QtCore.Signal documentation
582     Python slots don't get called when they have a custom decorator
589     Crash related to QGraphicsProxyWidget and QVariant
592     shiboken.dll produces a segmentation fault when reloading a PySide module
608     Photoviewer example missing license boilerplates and shebang lines
609     Python site-packages path cannot be customized
610     QWidgetItemV2 not exposed to Python
626     Problem building PySide on OS X (qabstractfileengine_wrapper.cpp:
No such file or directory)
406     Unable to send instant messages using QMessageService
458     Doesn't build with QtMobility 1.1.0~beta2
487     Support QContactDetailFieldDefinition.setAllowableTypes
497     Miising __lt__ operators in QtMobility::QGeoMapObject
499     QFeedbackHapticsInterface and QFeedbackFileInterface are broken
511     QPainter doesn't respect Qt.NoPen
522     example/threads/mandelbrot.py crashes on exit
523     QWidget.winId() returns PyCObject (expected unsigned long)
530     Importing division from future breaks QPoint division
531     sessionProperty "ConnectInBackground" does not work
539     MCC and MNC interchanged
541     QTableWidget.itemAt(row, col) always returns item at 0, 0.
550     Can't call PySide slot from QtScript when the args are a list of anything.
556     QGraphicsScene.addItem performs very poorly when the scene has &gt;10000 items
562     pyside-uic does not generate some layers properties
568     List insertion time grows with list size
574     In docs of QUuid there's documentation for a function called
"operator QString"
575     Strange behaviour of QTextEdit.ExtraSelection().cursor
584     python pickle module can't treat QByteArray object of PySide
591     QtCore.QRect has no attribute "getRect()" in Windows binary
611     enum values lack a tp_print implementation
614     FAil to register 2 objects in the same address
619     never automatically delete a QWidget that has no parent widget and
is visible
620     QAbstractItemModel.createIndex(int,int,PyObject*) does not
increment refcount
621     QGLWidget.bindTexture(QString) does not bind the texture correctly
622     PPA pyside is broken on Ubuntu 10.10
623     QGLWidget.bindTexture(QPixmap, GLenum, GLenum) is missing
625     QFileDialog return a tuple instead of a unicode
628     pyside-uic can't effect "headerVisible" attribute for QTreeView
and QTreeWidget
232     [FTBFS] Fails to build on hurd-i386 (Test "lock" hangs for more
than 191 minutes)
255     Test qtscripttools_debugger segfaults on ia64
298     Contact subtype not correctly set



References
==========

[1] &lt;a href="http://developer.qt.nokia.com/wiki/PySideDownloads"&gt;http://developer.qt.nokia.com/wiki/PySideDownloads&lt;/a&gt;
[2] &lt;a href="http://qt.gitorious.org/pyside"&gt;http://qt.gitorious.org/pyside&lt;/a&gt;
[3] &lt;a href="http://bugs.openbossa.org/"&gt;http://bugs.openbossa.org/&lt;/a&gt;
[4] &lt;a href="http://www.pyside.org/docs/pseps/psep-0001.html"&gt;http://www.pyside.org/docs/pseps/psep-0001.html&lt;/a&gt;

Thanks
PySide team.
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-588728865863622527?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/588728865863622527/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/01/pyside-python-for-qt-version-100beta4-i.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/588728865863622527?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/588728865863622527?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/01/pyside-python-for-qt-version-100beta4-i.html" title="[PySide] Python for Qt version 1.0.0~beta4 &quot;I have altered the deal&quot; released" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;Ak4MSXY8fyp7ImA9Wx9WE0U.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-4054234440240055413</id><published>2011-01-18T14:16:00.000-08:00</published><updated>2011-01-18T14:16:28.877-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-18T14:16:28.877-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pyside" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Python GUIniverse</title><content type="html">I am on the &lt;a href="http://pyside.org"&gt;PySide&lt;/a&gt; of the Force.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-4054234440240055413?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/4054234440240055413/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/01/python-guiniverse.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/4054234440240055413?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/4054234440240055413?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/01/python-guiniverse.html" title="Python GUIniverse" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkAMQ3k-fip7ImA9Wx9XFEQ.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-6753018075190080454</id><published>2011-01-08T05:52:00.000-08:00</published><updated>2011-01-08T05:53:02.756-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-08T05:53:02.756-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mercurial" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="svn" /><category scheme="http://www.blogger.com/atom/ns#" term="py2exe" /><title>Injecting SVN bindings into Mercurial on Windows</title><content type="html">If you need to add &lt;a href="http://alagazam.net/"&gt;Subversion bindings&lt;/a&gt; for your Mercurial, which was installed using ordinary installer (and not &lt;a href="http://tortoisehg.bitbucket.org/"&gt;TortoiseHg&lt;/a&gt;), then the following script can help to put all files in place.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://bitbucket.org/techtonik/py2exe-relibzip/src/f15f8d032b5b/reinject.py"&gt;https://bitbucket.org/techtonik/py2exe-relibzip/src/f15f8d032b5b/reinject.py&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Unpack svn bindings, add all *.py files from svn/ and libsvn/ directories into the root of library.zip archive *with* these directories. Then call script with path to unpacked libsvn/. The script will generate some *.dll and *.py files in current directory. Put *.py into library.zip:/libsvn/ and *.dll into Mercurial installation directory. You may need to also copy libsvn_swig_py-1.dll into Mercurial dir.&lt;br /&gt;
&lt;br /&gt;
The script can be tuned to insert C extensions to any py2exe distribution compiled with bundle_files=3&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-6753018075190080454?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/6753018075190080454/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2011/01/injecting-svn-bindings-into-mercurial.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6753018075190080454?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6753018075190080454?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2011/01/injecting-svn-bindings-into-mercurial.html" title="Injecting SVN bindings into Mercurial on Windows" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUcFSHw-eSp7ImA9Wx9SGUU.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-7065137041774403613</id><published>2010-12-10T04:10:00.000-08:00</published><updated>2010-12-10T04:10:19.251-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-10T04:10:19.251-08:00</app:edited><title>Got mail? Part II</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_-WP64rPqC8g/TQIYOD1QsYI/AAAAAAAAAXQ/YW4m975PbEU/s1600/ohno.png" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="80" width="93" src="http://1.bp.blogspot.com/_-WP64rPqC8g/TQIYOD1QsYI/AAAAAAAAAXQ/YW4m975PbEU/s320/ohno.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br clear="both"/&gt;&lt;br /&gt;
See &lt;a href="http://techtonik.rainforce.org/2007/01/got-mail.html"&gt;Part I&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-7065137041774403613?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/7065137041774403613/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/12/got-mail-part-ii.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/7065137041774403613?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/7065137041774403613?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/12/got-mail-part-ii.html" title="Got mail? Part II" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_-WP64rPqC8g/TQIYOD1QsYI/AAAAAAAAAXQ/YW4m975PbEU/s72-c/ohno.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkUARn4-eyp7ImA9Wx5aFE0.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-6158535512976843323</id><published>2010-11-10T07:50:00.000-08:00</published><updated>2010-11-10T07:50:47.053-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-10T07:50:47.053-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ssl" /><category scheme="http://www.blogger.com/atom/ns#" term="https" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><title>Validating SSL server certificate with Python 2.x</title><content type="html">&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;SSL stands for&amp;nbsp;&lt;strong&gt;Secure Sockets Layer&lt;/strong&gt;&amp;nbsp;and is designed to create secure connection between client and server. Secure means that connection is encrypted and therefore protected from eavesdropping. It also allows to validate site identity when connecting with HTTPS protocol.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;However, there is a &lt;a href="http://bugs.python.org/issue1589"&gt;bug&lt;/a&gt; in&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;&lt;strong&gt;ssl&lt;/strong&gt;&amp;nbsp;module from standard library of Python 2.x,&amp;nbsp;that allows successful &lt;a href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack"&gt;MITM&lt;/a&gt; attack using valid certificate from other site.&amp;nbsp;Basically, module checks&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;when connecting&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;&amp;nbsp;that server certificate is valid and correctly signed by root certificate, but it does not check that certificate actually belongs to the site, i.e. that site name matches the name specified in certificate.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;It is still possible to validate server identity in Python 2.6 manually. Let's start with illustration of the vulnerability.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif; font-size: 15px; line-height: 17px;"&gt;The following snippet should fail - it replaces HOST "www.google.com" to connect to with its IP address. If you try to use this IP in Chrome like&amp;nbsp;&lt;a class="https" href="https://74.125.232.50/" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: dashed; border-bottom-width: 1px; color: #0000aa; text-decoration: none;"&gt;https://74.125.232.50&lt;/a&gt;&amp;nbsp;- it will show an error, but&amp;nbsp;&lt;strong&gt;ssl&lt;/strong&gt;&amp;nbsp;library will not throw exception.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code class="prettyprint"&gt;import socket&lt;br /&gt;
import ssl&lt;br /&gt;
&lt;br /&gt;
HOST = "www.google.com"&lt;br /&gt;
PORT = 443&lt;br /&gt;
&lt;br /&gt;
# replace HOST name with IP, this should fail connection attempt,&lt;br /&gt;
# but it doesn't in Python 2.x&lt;br /&gt;
HOST = socket.getaddrinfo(HOST, PORT)[0][4][0]&lt;br /&gt;
print(HOST)&lt;br /&gt;
&lt;br /&gt;
# create socket and connect to server&lt;br /&gt;
# server address is specified later in connect() method&lt;br /&gt;
sock = socket.socket()&lt;br /&gt;
sock.connect((HOST, PORT))&lt;br /&gt;
&lt;br /&gt;
# wrap socket to add SSL support&lt;br /&gt;
sock = ssl.wrap_socket(sock,&lt;br /&gt;
  # flag that certificate from the other side of connection is&lt;br /&gt;
  # required and should be validated when wrapping &lt;br /&gt;
  cert_reqs=ssl.CERT_REQUIRED,&lt;br /&gt;
  # file with root certificates&lt;br /&gt;
  ca_certs="cacert.pem"&lt;br /&gt;
)&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;div style="font-size: 15px; line-height: 17px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 15px; line-height: 17px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 15px; line-height: 17px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;You will need cacert.pem file with root certificates. Just&amp;nbsp;grab the latest version from&amp;nbsp;&lt;a class="http" href="http://curl.haxx.se/ca/cacert.pem" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: dashed; border-bottom-width: 1px; color: #0000aa; text-decoration: none;"&gt;http://curl.haxx.se/ca/cacert.pem&lt;/a&gt;&amp;nbsp;This code above won't give you any error. Replace HOST value with&amp;nbsp;&lt;a class="https" href="https://www.debian-administration.org/" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: dashed; border-bottom-width: 1px; color: #0000aa; text-decoration: none;"&gt;https://www.debian-administration.org/&lt;/a&gt;&amp;nbsp;to check that certificate validation actually works.&amp;nbsp;This site's certificate is not signed by any root certificates from "cacerts.txt", so you get an error.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 15px; line-height: 17px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 15px; line-height: 17px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;To validate that a certificate matches requested site, you need to check&amp;nbsp;&lt;em&gt;commonName&lt;/em&gt;&amp;nbsp;field in the&amp;nbsp;&lt;em&gt;subject&lt;/em&gt;&amp;nbsp;of the certificate. This information can be accessed with&amp;nbsp;&lt;em&gt;&lt;a href="http://docs.python.org/release/2.6.6/library/ssl.html#ssl.SSLSocket.getpeercert"&gt;getpeercert&lt;/a&gt;()&lt;/em&gt;&amp;nbsp;method of wrapped socket.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 15px; line-height: 17px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;code class="prettyprint"&gt;import socket&lt;br /&gt;
import ssl&lt;br /&gt;
&lt;br /&gt;
HOST = "www.google.com"&lt;br /&gt;
PORT = 443&lt;br /&gt;
&lt;br /&gt;
# replace HOST name with IP, this should fail connection attempt&lt;br /&gt;
HOST = socket.getaddrinfo(HOST, PORT)[0][4][0]&lt;br /&gt;
print(HOST)&lt;br /&gt;
&lt;br /&gt;
# create socket and connect to server&lt;br /&gt;
# server address is specified later in connect() method&lt;br /&gt;
sock = socket.socket()&lt;br /&gt;
sock.connect((HOST, PORT))&lt;br /&gt;
&lt;br /&gt;
# wrap socket to add SSL support&lt;br /&gt;
sock = ssl.wrap_socket(sock,&lt;br /&gt;
# flag that certificate from the other side of connection is&lt;br /&gt;
# required and should be validated when wrapping &lt;br /&gt;
cert_reqs=ssl.CERT_REQUIRED,&lt;br /&gt;
# file with root certificates&lt;br /&gt;
ca_certs="cacerts.txt"&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# manual check of hostname&lt;br /&gt;
cert = sock.getpeercert()&lt;br /&gt;
for field in cert['subject']:&lt;br /&gt;
if field[0][0] == 'commonName':&lt;br /&gt;
certhost = field[0][1]&lt;br /&gt;
if certhost != HOST:&lt;br /&gt;
raise ssl.SSLError(&lt;br /&gt;
    "Host name '%s' doesn't match certificate host '%s'"&lt;br /&gt;
    % (HOST, certhost))&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Verdana, Geneva, 'Bitstream Vera Sans', Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;That's it. I put my findings to &lt;a href="http://wiki.python.org/moin/SSL"&gt;http://wiki.python.org/moin/SSL&lt;/a&gt; - you may want check it for updates.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-6158535512976843323?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/6158535512976843323/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/11/validating-ssl-server-certificate-with.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6158535512976843323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6158535512976843323?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/11/validating-ssl-server-certificate-with.html" title="Validating SSL server certificate with Python 2.x" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUcBQn45fCp7ImA9WhZQF08.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-1385713340840784947</id><published>2010-09-22T13:05:00.000-07:00</published><updated>2011-04-25T02:17:33.024-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-25T02:17:33.024-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="hg" /><category scheme="http://www.blogger.com/atom/ns#" term="vcs" /><category scheme="http://www.blogger.com/atom/ns#" term="svn" /><category scheme="http://www.blogger.com/atom/ns#" term="py2exe" /><category scheme="http://www.blogger.com/atom/ns#" term="hack" /><title>hgsubversion: Installing on Windows</title><content type="html">&lt;ul style="font-family: arial, sans-serif; font-size: small; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre-wrap;"&gt;&lt;span class="Apple-style-span" style="color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; white-space: normal;"&gt;&lt;ul style="font-family: arial, sans-serif; font-size: small; line-height: 1.4; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre-wrap;"&gt;&lt;span class="Apple-style-span" style="color: black; line-height: normal;"&gt;&lt;ul style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;I use Windows primarily, and it's not easy to install Mercurial extensions there if they are not bundled with Mercurial installer itself. I am using plain .msi installer, which doesn't include &lt;span style="font-weight: bold;" x="y"&gt;hgsubversion&lt;/span&gt;, so I'll show you how to get this extension in place manually.

Suppose you have Mercurial installed into C:\Mercurial Go there and notice &lt;span style="font-weight: bold;" x="y"&gt;library.zip&lt;/span&gt; archive. This is where you should add &lt;span style="font-weight: bold;" x="y"&gt;hgsubversion&lt;/span&gt;. &lt;span style="font-weight: bold;" x="y"&gt;library.zip&lt;/span&gt; has the following structure:

/
+-- email
+-- encodings
+-- hgext
+-- logging
...
__future__.pyc
_abcoll.pyc
_elementtree.pyd
...
zipextimporter.pyc
zipfile.pyc

Contents of this archive is the whole Mercurial code. Code is written in Python, and is compiled into .pyc and .pyd files for speed and packed into &lt;span style="font-weight: bold;" x="y"&gt;library.zip&lt;/span&gt; for convenience. For interpreted languages like Python it is not necessary to compile source files for execution, but they did it.

Get latest &lt;span style="font-weight: bold;" x="y"&gt;hgsubversion&lt;/span&gt; sources from &lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Fbitbucket.org%2Fdurin42%2Fhgsubversion%2Fsrc" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;http://bitbucket.org/durin42/hgsubversion/src&lt;/a&gt; by pressing link "get source" in upper right corner. Or download released version from &lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Fpypi.python.org%2Fpypi%2Fhgsubversion%2F1.1.2" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;http://pypi.python.org/pypi/hgsubversion/1.1.2&lt;/a&gt;

Unpack archive. You should have directory structure like:

/
+-- hgsubversion
+-- notes
+-- tests
+-- tools
.hgignore
...
setup.py

Now put hgsubversion/ dir from this structure into &lt;span style="font-weight: bold;" x="y"&gt;library.zip&lt;/span&gt; archive, inside hgext/ directory, where Mercurial expects to find its extensions.

Enable extension by uncommenting line ";hgsubversion =" in &lt;span style="font-weight: bold;" x="y"&gt;Mercurial.ini&lt;/span&gt; that is usually located in your profile directory, i.e. C:\Users\yourname If it is not there - copy one from your &lt;span style="font-weight: bold;" x="y"&gt;C:\Mercurial\hgrc.d&lt;/span&gt; directory. Try to checkout some subversion repository. You will get an error like this:

C:\p&amp;gt;hg clone &lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Fgoogle-twitter.googlecode.com%2Fsvn%2Ftrunk" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;http://google-twitter.googlecode.com/svn/trunk&lt;/a&gt;
(falling back to static-http)
(falling back to Subversion support)
destination directory: trunk
abort: subvertpy 0.7.3 or later required, but not found!

You need Subversion bindings for Python. They advertise subvertpy, but it is also possible to use official bindings. Those bindings is just a set of libraries that allows Python scripts to use Subversion binary code directly. Unfortunately, after migration to &lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Fapache.org" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;apache.org&lt;/a&gt;, Subversion bindings are not compiled anymore, so there is no official place where you can download them. But thanks to &lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Falagazam.net%2F" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;http://&lt;/a&gt;&lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Falagazam.net%2F" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;alagazam&lt;/a&gt;&lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Falagazam.net%2F" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;.net/&lt;/a&gt; it is possible to get unofficial .

Download &lt;span style="font-weight: bold;" x="y"&gt;svn-win32-1.6.12_py.zip&lt;/span&gt; or more up-to-date distribution and extract it. You will get a directory structure like:

/
+-- python
+-- libsvn
+-- svn
README.txt

In libsvn/ rename _client.dll to _client.pyd. Do the same with _core.dll, _delta.dll, _ra.dll
Maybe you'll have to rename other .dll files, but these were enough for me. Now put svn/ and libsvn/ into the library.zip directly in the root. I also had to copy intl3_svn.dll from an old 1.6.6 installation of SVN into library.zip root (you may find this file in Windows binaries archive from &lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Falagazam.net%2F" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;http://&lt;/a&gt;&lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Falagazam.net%2F" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;alagazam&lt;/a&gt;&lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http%3A%2F%2Falagazam.net%2F" style="color: #003ea8; font-family: arial, sans-serif;" target="_blank" x="y"&gt;.net/&lt;/a&gt;) and place libsvn_swig_py-1.dll from libsvn/ dir also in library.zip root.

It should work now.&lt;span class="__wave_paste" data-wave-annotations="242,254,style%2FfontWeight,bold:396,407,style%2FfontWeight,bold:446,458,style%2FfontWeight,bold:460,471,style%2FfontWeight,bold:797,808,style%2FfontWeight,bold:954,966,style%2FfontWeight,bold:980,1025,link%2Fmanual,http%3A%2F%2Fbitbucket.org%2Fdurin42%2Fhgsubversion%2Fsrc:1113,1159,link%2Fmanual,http%3A%2F%2Fpypi.python.org%2Fpypi%2Fhgsubversion%2F1.1.2:1357,1368,style%2FfontWeight,bold:1513,1526,style%2FfontWeight,bold:1641,1660,style%2FfontWeight,bold:2364,2384,link%2Fmanual,http%3A%2F%2Falagazam.net%2F:2432,2455,style%2FfontWeight,bold:2995,3015,link%2Fmanual,http%3A%2F%2Falagazam.net%2F:" data-wave-xml="hgsubversion: Installing on Windows&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;I am using Windows primarily, and it's not very easy to install Mercurial extensions there if they are not bundled with Mercurial installer itself. I am using plain .msi installer, which doesn't include hgsubversion, so I'll show you how to get this extension in place manually.&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Suppose you have Mercurial installed into C:\Mercurial Go there and notice library.zip archive. This is where you should add hgsubversion. library.zip has the following structure:&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;/&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- email&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- encodings&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- hgext&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- logging&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;...&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;__future__.pyc&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;_abcoll.pyc&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;_elementtree.pyd&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;...&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;zipextimporter.pyc&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;zipfile.pyc&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Contents of this archive is the whole Mercurial code. Code is written in Python, and is compiled into .pyc and .pyd files for speed and packed into library.zip for convenience. For interpreted languages like Python it is not necessary to compile source files for execution, but they did it.&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Get latest hgsubversion sources from http://bitbucket.org/durin42/hgsubversion/src by pressing link &amp;quot;get source&amp;quot; in upper right corner. Or download released version from http://pypi.python.org/pypi/hgsubversion/1.1.2&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Unpack archive. You should have directory structure like:&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;/&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- hgsubversion&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- notes&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- tests&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- tools&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;.hgignore&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;...&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;setup.py&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Now put hgsubversion/ dir from this structure into library.zip archive, inside hgext/ directory, where Mercurial expects to find its extensions.&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Enable extension by uncommenting line &amp;quot;;hgsubversion =&amp;quot; in Mercurial.ini that is usually located in your profile directory, i.e. C:\Users\yourname If it is not there - copy one from your C:\Mercurial\hgrc.d directory. Try to checkout some subversion repository. You will get an error like this:&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;C:\p&amp;amp;gt;hg clone http://google-twitter.googlecode.com/svn/trunk&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;(falling back to static-http)&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;(falling back to Subversion support)&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;destination directory: trunk&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;abort: subvertpy 0.7.3 or later required, but not found!&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;You need Subversion bindings for Python. They advertise subvertpy, but it is also possible to use official bindings. Those bindings is just a set of libraries that allows Python scripts to use Subversion binary code directly. Unfortunately, after migration to apache.org, Subversion bindings are not compiled anymore, so there is no official place where you can download them. But thanks to http://alagazam.net/ it is possible to get unofficial .&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Download svn-win32-1.6.12_py.zip or more up-to-date distribution and extract it. You will get a directory structure like:&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;/&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;+-- python&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;    +-- libsvn&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;    +-- svn&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;README.txt&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;In libsvn/ rename _client.dll to _client.pyd. Do the same with _core.dll, _delta.dll, _ra.dll&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;Maybe you'll have to rename other .dll files, but these were enough for me. Now put svn/ and libsvn/ into the library.zip directly in the root. I also had to copy intl3_svn.dll from an old 1.6.6 installation of SVN into library.zip root (you may find this file in Windows binaries archive from http://alagazam.net/) and place libsvn_swig_py-1.dll from libsvn/ dir also in library.zip root.&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;&amp;lt;line&amp;gt;&amp;lt;/line&amp;gt;It should work now."&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/ul&gt;&lt;/span&gt;&lt;/ul&gt;&lt;/span&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-1385713340840784947?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/1385713340840784947/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/09/hgsubversion-installing-on-windows.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1385713340840784947?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1385713340840784947?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/09/hgsubversion-installing-on-windows.html" title="hgsubversion: Installing on Windows" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0QNSXY6eCp7ImA9WxFWGEw.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-1259639859970685026</id><published>2010-06-06T01:03:00.000-07:00</published><updated>2010-06-06T01:03:18.810-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-06T01:03:18.810-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="flow" /><title>Users read only first sentence</title><content type="html">During the work on Python documentation somebody joked that users look only at first sentence. I would say that in the Age of Twitter it is a rule. So I should swap the first two sentences (and switch to microblogging).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-1259639859970685026?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/1259639859970685026/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/06/users-read-only-first-sentence.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1259639859970685026?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1259639859970685026?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/06/users-read-only-first-sentence.html" title="Users read only first sentence" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEIERXw-eyp7ImA9WxFQEUk.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-1768740037123262699</id><published>2010-05-06T04:48:00.000-07:00</published><updated>2010-05-06T04:48:24.253-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-06T04:48:24.253-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="pdf" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="sphinx" /><title>Sphinx PDF with rst2pdf</title><content type="html">I deliberately omit word LaT*X in my post to avoid missing people who add '-LaT*X' in search queries. Yes, it is possible to generate PDF with &lt;a href="http://sphinx.pocoo.org/"&gt;Sphinx&lt;/a&gt; without LaT*X in cross-platform way. Yes, on Windows too. You will need only &lt;a href="http://code.google.com/p/rst2pdf/"&gt;rst2pdf&lt;/a&gt;. Actually integration with Sphinx is well described in rst2pdf manual (&lt;a href="http://rst2pdf.googlecode.com/svn/trunk/doc/manual.txt"&gt;text&lt;/a&gt; and &lt;a href="http://lateral.netmanagers.com.ar/static/manual.pdf"&gt;PDF&lt;/a&gt;), but people find it hard to find this information, so I'll quote checklist here:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;install rst2pdf&lt;/li&gt;
&lt;li&gt;register rst2pdf in your &lt;b&gt;conf.py&lt;/b&gt; Sphinx config&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;extensions = ['sphinx.ext.autodoc','rst2pdf.pdfbuilder']&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;run&lt;br /&gt;
&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sphinx-build -bpdf sourcedir outdir&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;I hope it was helpful. Actually, check the manual - it has some useful options for &lt;b&gt;conf.py&lt;/b&gt; and it's more up-to-date. &lt;br /&gt;
&lt;ol&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-1768740037123262699?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/1768740037123262699/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/05/sphinx-pdf-with-rst2pdf.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1768740037123262699?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1768740037123262699?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/05/sphinx-pdf-with-rst2pdf.html" title="Sphinx PDF with rst2pdf" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>5</thr:total></entry><entry gd:etag="W/&quot;DE4ARnY4fip7ImA9WxFREE0.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-5820163268062655916</id><published>2010-04-23T00:08:00.000-07:00</published><updated>2010-04-23T00:15:47.836-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-23T00:15:47.836-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><category scheme="http://www.blogger.com/atom/ns#" term="tip" /><category scheme="http://www.blogger.com/atom/ns#" term="far manager" /><category scheme="http://www.blogger.com/atom/ns#" term="console" /><title>Why Far Manager and Vim are awesome</title><content type="html">&lt;a href="http://www.farmanager.com/"&gt;Far Manager&lt;/a&gt;&amp;nbsp;and &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt;&amp;nbsp;are both console tools. When non-computer folks see blue panels of &lt;b&gt;Far&lt;/b&gt; on my screen they are usually surprised like "&lt;b&gt;DOS? But why?&lt;/b&gt;". These folks still remember DOS windows (DOS Windows, huh), but if some fourteen years adult tells me something about DOS it will be my turn to be surprised.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Far Manager&lt;/b&gt; is essentially a&amp;nbsp;Windows console&amp;nbsp;Swiss Army Knife. Much like &lt;b&gt;Vim&lt;/b&gt;&amp;nbsp;is for Unix. While GUI tools are awesome, they are not as responsive as console ones, &lt;i&gt;not deterministic&lt;/i&gt;&amp;nbsp;- I know it sounds horrible, but it just means that at any given moment you can't be sure what a given combination of &amp;nbsp;keys will do. It depends on the focus and this focus is not always clearly visible. Interaction using mouse is slow (if you're not a hardcore gamer, of course). But I actually written this post to say that:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;You don't need to press "ENTER" for most used commands and that is awesome!&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;In Far you may setup shortcuts as easy as pressing&amp;nbsp;&lt;b&gt;F2&lt;/b&gt;&amp;nbsp;and then&amp;nbsp;&lt;b&gt;Ins&lt;/b&gt;. Every action is reachable as a series of key presses. You don't need to put you hand off the keyboard to reach the mouse. Forget about mouse - you will need it only for copy/pasting. You may easily automate repeated key pressing by using &lt;b&gt;Ctrl-.&lt;/b&gt;&amp;nbsp;then typing the keys you like and then hitting &lt;b&gt;Ctrl-.&lt;/b&gt;&amp;nbsp;again. You'll be prompted for a key combination that will invoke the keys you've just written. Repeated edits, replacements, file renames, copies - a lot of things can be automated using this shortcut called &lt;b&gt;Macro&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Another from many&amp;nbsp;&lt;b&gt;Far features&lt;/b&gt; you may find awesome is output redirection. By using &lt;b&gt;edit:&amp;lt;&lt;/b&gt;&amp;nbsp;prefix on the command line you may redirect the output to embedded editor and navigate around it as you like. With &lt;b&gt;&lt;a href="http://colorer.sf.net/"&gt;Colorer&lt;/a&gt;&lt;/b&gt;&amp;nbsp;plugin you will even get syntax highlight for the output.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Enjoy!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-5820163268062655916?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/5820163268062655916/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/04/why-far-manager-and-vim-are-awesome.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/5820163268062655916?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/5820163268062655916?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/04/why-far-manager-and-vim-are-awesome.html" title="Why Far Manager and Vim are awesome" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUcASXoyfip7ImA9WxFRFU8.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-8041874678235561723</id><published>2010-04-14T05:57:00.000-07:00</published><updated>2010-04-29T00:44:08.496-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-29T00:44:08.496-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Porting Python applications from Unix to Windows</title><content type="html">&lt;h3&gt;os.open&lt;/h3&gt;Note the difference between &lt;a href="http://docs.python.org/library/functions.html?highlight=open#open"&gt;open&lt;/a&gt; and &lt;a href="http://docs.python.org/library/os.html#os.open"&gt;os.open&lt;/a&gt; and ensure that all &lt;b&gt;os.open&lt;/b&gt; calls have &lt;b&gt;os.O_BINARY&lt;/b&gt; flag for Windows.&lt;br /&gt;
&lt;br /&gt;
See also Stani and Nadia talk about &lt;a href="http://pythonide.blogspot.com/2010/02/why-i-am-going-to-talk-at-pycon.html"&gt;cross platform application development and distribution&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-8041874678235561723?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/8041874678235561723/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/04/porting-python-applications-from-unix.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8041874678235561723?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8041874678235561723?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/04/porting-python-applications-from-unix.html" title="Porting Python applications from Unix to Windows" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUAHQnk7fyp7ImA9WxBWEk0.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-2577872102945704640</id><published>2010-02-03T06:22:00.000-08:00</published><updated>2010-02-03T06:35:33.707-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-03T06:35:33.707-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="api" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><category scheme="http://www.blogger.com/atom/ns#" term="hack" /><category scheme="http://www.blogger.com/atom/ns#" term="cgi" /><title>URL parameters in action method of HTML form are lost for GET request</title><content type="html">Surprisingly how experienced web-developers may miss some basic nuances of form processing that exist for many-many years. One of them is the fact that URL parameters added to &lt;i&gt;action&lt;/i&gt; attribute of &lt;i&gt;&amp;lt;form&amp;gt;&lt;/i&gt; element are lost for GET requests.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;code class="prettyprint"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;Query string from action attribute is killed for GET request&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;form name="getSearchForm" action="?missed=one" method="get"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;input type="text" name="q" value="s" /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;button class="searchButton" type="submit"&amp;gt;GET&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;form name="postSearchForm" action="?missed=one" method="post"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;input type="text" name="q" value="s" /&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;button class="searchButton" type="submit"&amp;gt;POST&amp;lt;/button&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/form&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&amp;nbsp;&lt;/code&gt;&lt;br /&gt;The parameter &lt;span style="font-style:italic;"&gt;"missed=one"&lt;/span&gt; is missing from URL after clicking a button on a form with GET send method. It is present for POST form though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-2577872102945704640?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/2577872102945704640/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/02/url-parameters-in-action-method-of-html.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/2577872102945704640?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/2577872102945704640?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/02/url-parameters-in-action-method-of-html.html" title="URL parameters in action method of HTML form are lost for GET request" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D08MRHg4cCp7ImA9WxBXF0s.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-6913194484792343394</id><published>2010-01-29T03:51:00.000-08:00</published><updated>2010-01-29T03:51:25.638-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-29T03:51:25.638-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="flow" /><title>Working with complex issues</title><content type="html">Some issues should be&amp;nbsp;cut into chewable &lt;span class="Apple-style-span" style="font-family: arial, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;chunks and linked&amp;nbsp;together into a dependency tree. Each chunk should be accompanied by "digestion recipe" that includes tools, skills and necessary ingredients. If the issue is very complicated, the chunks may be split in pieces that take no longer than one day to get the chunk, analyze it and solve. The work on the issue can then be spread&amp;nbsp;over the looong time.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;This requires tools. Tools to minimize waste of time on getting all necessary stuff to start work, save work, send it in one day and wait for it to be approved. Learning these tools&amp;nbsp;should also be quick to get the task done.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: small;"&gt;Life is short, so time savers are critical. Cheatsheet template with already filled address of contacts, repositories etc. can greatly reduce the time to get the thing done. Once template is filled, it is the a cheatsheet that can be commented with new information for this specific task. These comments can then be incorporated back to original template or into a new, for more advanced usage.&amp;nbsp;If making a reusable template is just one hour, and solution for the task is one day - a template one day and the task the other is better.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-6913194484792343394?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/6913194484792343394/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/01/working-with-complex-issues.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6913194484792343394?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/6913194484792343394?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/01/working-with-complex-issues.html" title="Working with complex issues" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DE8MR34yfyp7ImA9WhdaEk0.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-3943252626117978019</id><published>2010-01-25T07:06:00.000-08:00</published><updated>2011-10-21T07:21:26.097-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-21T07:21:26.097-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="py2exe" /><title>Repacking library.zip from py2exe</title><content type="html">&lt;b&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;/div&gt;
&lt;b&gt;intro&lt;/b&gt;&lt;br /&gt;
&lt;div style="margin: 0px;"&gt;
py2exe tool converts Python scripts to standalone .exe distributives. It isolates all required Python modules together with Python interpreter itself and wraps them into single library.zip file. This way application is not affected by Python modules that may be already installed on user system. Unfortunately, this also means that you can't add new modules to your standalone Python program.&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
For example, you need to add &lt;a href="http://hg-git.github.com/"&gt;Hg-Git&lt;/a&gt; extension to &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; installed as standalone program. You can specify path to extension in &lt;i&gt;Mercurial.ini&lt;/i&gt;, but Hg-Git depends on &lt;a href="http://samba.org/%7Ejelmer/dulwich/"&gt;Dulwich&lt;/a&gt; module, which is not present in &lt;i&gt;library.zip&lt;/i&gt; Attempt to use this extension will fail. The same problem is with converting Bazaar repositories using &lt;i&gt;convert&lt;/i&gt; extension that is present in library.zip, but additionally requires installed &lt;i&gt;bzr&lt;/i&gt; module.&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
&lt;b&gt;solution&lt;/b&gt;&lt;/div&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
The script below helps to add Python modules to library.zip file made with py2exe. Latest version should be available at &lt;a href="http://bitbucket.org/techtonik/py2exe-relibzip/src/"&gt;this bitbucket repository&lt;/a&gt;. The following command unpacks &lt;i&gt;library.zip&lt;/i&gt; in current directory and makes &lt;i&gt;library_unpacked.zip&lt;/i&gt; that you can edit with your favorite archiver:&lt;/div&gt;
&lt;br /&gt;
&lt;code class="prettyprint"&gt;python relibzip.py unpack&lt;/code&gt;&lt;br /&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
After you've finished, issue:&lt;/div&gt;
&lt;br /&gt;
&lt;code class="prettyprint"&gt;python relibzip.py pack&lt;/code&gt;&lt;br /&gt;
&lt;div&gt;
and script will create &lt;i&gt;library_packed.zip&lt;/i&gt; from extracted resources. Copy this file over &lt;i&gt;library.zip&lt;/i&gt; and you all set.&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
Source code (ugly, but works):&lt;br /&gt;
&lt;pre&gt;&lt;code class="prettyprint"&gt;
"""
pack/unpack library.zip created by py2exe to standard .zip archive

library.zip created with py2exe can not always be processed by standard
archivers. this script removes extra chunks added by py2exe and puts
them back when requested

MIT license, by techtonik // gmail.com
"""

import sys
import os
from optparse import OptionParser
import struct


PYTHONDLL = "&amp;lt;pythondll&gt;"
PDNAME = "pythondll"
ZLIBPYD = "&amp;lt;zlib.pyd&gt;"
ZDNAME = "zlibpyd"

UNPACKED = "library_unpacked.zip"
PACKED = "library_packed.zip"


def unpack(filename):
   f = open(filename, "rb")
   # looking for PYTHONDLL name
   pdname = f.read(len(PYTHONDLL))
   if pdname != PYTHONDLL:
       if pdname[:2] == "PK":
           sys.exit("Seems to be normal .zip archive, not unpacking")
       else:
           sys.exit("Unknown archive format")

   def save_section(secname, fname):
       print "Extracting %s section to %s" % (secname, fname)
       fsize = struct.unpack("i", f.read(4))[0]
       fpd = open(fname, "wb")
       fpd.write(f.read(fsize))
       fpd.close()
   save_section(PYTHONDLL, PDNAME)

   buf = ""
   zdname = f.read(len(ZLIBPYD))
   if zdname != ZLIBPYD:
       if zdname[:2] == "PK":
           print "No zlib.pyd section"
           buf = zdname
       else:
           sys.exit("Unknown archive format")
   else:
       save_section(ZLIBPYD, ZDNAME)
  
   flib = open(UNPACKED, "wb")
   flib.write(buf)
   flib.write(f.read())
   flib.close()
   f.close()
   print "Done. Unpacked .zip contents is available at %s" % UNPACKED
   sys.exit(0)


def pack(tofname):

   if not os.path.exists(PDNAME):
       sys.exit("%s section file %s is not found. Exiting" % (PYTHONDLL, PDNAME))
   if not os.path.exists(UNPACKED):
       sys.exit("Unpacked version %s is not found. Exiting" % UNPACKED)

   f = open(tofname, "wb")

   def write_section(secname, fname):
       print "Writing %s section from %s" % (secname,fname)
       f.write(PYTHONDLL)
       fsize = os.stat(PDNAME).st_size
       f.write(struct.pack("i", fsize))

       fpd = open(fname, "rb")
       f.write(fpd.read())
       fpd.close()
       print "Removing section file %s" % fname
       os.remove(fname)
   write_section(PYTHONDLL, PDNAME)

   # check for optional ZLIBPYD section
   if not os.path.exists(ZDNAME):
       print "No %s section file %s. Skipping" % (ZLIBPYD, ZDNAME)
   else:
       write_section(ZLIBPYD, ZDNAME)

   fzip = open(UNPACKED, "rb")
   f.write(fzip.read())
   fzip.close()

   f.close()
   print "Done. Packed .zip contents is available at %s" % tofname
   sys.exit(0)


parser = OptionParser(usage="usage: %prog &lt;pack|unpack&gt;",
   description="update library.zip created by py2exe utility")
opt,arg = parser.parse_args()
  
if arg and arg[0] == 'unpack':
   unpack("library.zip")
elif arg and arg[0] == 'pack':
   pack(PACKED)
else:
   sys.exit(parser.format_help())

&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-3943252626117978019?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/3943252626117978019/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2010/01/repacking-libraryzip-from-py2exe.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/3943252626117978019?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/3943252626117978019?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2010/01/repacking-libraryzip-from-py2exe.html" title="Repacking library.zip from py2exe" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;Ak4MSX49cSp7ImA9WxBTEks.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-209558491613752787</id><published>2009-12-08T02:43:00.000-08:00</published><updated>2009-12-08T02:43:08.069-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-08T02:43:08.069-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>An ideal options / arguments parsing library for Python</title><content type="html">One of primary areas of Python applications is helper scripts and system utilities that are often called from command line. Even programming in Python itself is not comfortable without interactive mode at hand. That's why argument parsing libraries are important to some degree to many Python developers.&lt;br /&gt;
&lt;br /&gt;
There once was &lt;a href="http://docs.python.org/library/getopt.html#module-getopt"&gt;getopt&lt;/a&gt; library, but it was awkward compared to newer &lt;a href="http://docs.python.org/library/optparse.html"&gt;optparse&lt;/a&gt; module, but even &lt;b&gt;optparse&lt;/b&gt; nowadays is not enough for some who is willing to replace it with &lt;a href="http://code.google.com/p/argparse/"&gt;argparse&lt;/a&gt;.&lt;b&gt; optparse&lt;/b&gt; is a kind of "stable minimal API" that is not easy to push a change to. As a person who has a lot of Python command tools at hand I often feel that I need patched version of &lt;b&gt;optparse&lt;/b&gt;, but I can't afford managing dependencies or inserting a bulk of code into 5 minute script that should be as minimal and clear as possible for easy maintenance. So I wouldn't mind against more &lt;a href="http://argparse.googlecode.com/svn/trunk/doc/argparse-vs-optparse.html"&gt;featured&lt;/a&gt; &lt;b&gt;argparse&lt;/b&gt; library.&lt;br /&gt;
&lt;br /&gt;
However, &lt;b&gt;argparse&lt;/b&gt; can only be useful in standard library if it will be:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Minimalistic. Like &lt;i&gt;optparse&lt;/i&gt; won't take much brainspace to avoid referencing documentation for 80% of the stuff&lt;/li&gt;
&lt;li&gt;Easily extensible&lt;/li&gt;
&lt;li&gt;Contains copy/paste recipes for popular usages&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;On the first look &lt;b&gt;argparse&lt;/b&gt; is not minimalistic - even in &lt;a href="http://argparse.googlecode.com/svn/trunk/doc/ArgumentParser.html#ArgumentParser"&gt;constructor&lt;/a&gt; there are a lot of params that won't be used in 80% of cases and that could be easily moved into configuration methods.&lt;br /&gt;
&lt;br /&gt;
Is it easily extensible? It allows to specify &lt;b&gt;formatter class&lt;/b&gt;, &lt;b&gt;conflict_handler class&lt;/b&gt;, but it seems like you have very limited control over what will be matched as option and what as an argument. There are two options to constructor to define options prefix - &lt;a class="reference internal" href="http://argparse.googlecode.com/svn/trunk/doc/ArgumentParser.html#prefix-chars"&gt;prefix_chars&lt;/a&gt; and &lt;a class="reference internal" href="http://argparse.googlecode.com/svn/trunk/doc/ArgumentParser.html#fromfile-prefix-chars"&gt;fromfile_prefix_chars&lt;/a&gt;, but they are awkward. I wonder if I can provide /longarg on windows in addition to --longarg leaving also /s and -s options? It could be better done with the same custom class, which could be provided in recipes or as an optional import. &lt;br /&gt;
&lt;br /&gt;
There are no recipes in &lt;b&gt;argparse&lt;/b&gt;. That's bad, because that means the library is designed as a comprehensive solution to all command-line problems, but it still can't help me make the majority of my scripts more convenient without too much overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;argparse&lt;/b&gt; is not a huge leap from &lt;b&gt;optparse &lt;/b&gt;as the latter once was for &lt;b&gt;getopt&lt;/b&gt; in my opinion. For any argument parsing library to become a quality leap from &lt;b&gt;optparse&lt;/b&gt;, it should allow an easy way to build svn like command line interfaces with the following features:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;calling without arguments shows tool name, &lt;b&gt;version&lt;/b&gt; and usage info&lt;/li&gt;
&lt;li&gt;usage info contains either command list, options list or both&lt;/li&gt;
&lt;li&gt;"tool.py help &lt;command&gt;" is equivalent to "tool.py &lt;command&gt; -h"&lt;/command&gt;&lt;/command&gt;&lt;/li&gt;
&lt;li&gt;remove ugly default optparse help for options with arguments&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;-f FILE, --file=FILE  write report to FILE&lt;/pre&gt;&lt;pre style="font-family: inherit;"&gt;SVN is fine&lt;/pre&gt;&lt;pre&gt;-r [--revision] ARG      : ARG (some commands also take ARG1:ARG2 range)&lt;/pre&gt;&lt;pre style="font-family: inherit;"&gt;or Mercurial 
&lt;/pre&gt;&lt;pre&gt;-l --logfile       read commit message from &lt;file&gt; &lt;file&gt;
&lt;/file&gt;&lt;/file&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;cross-platform optional paging&lt;br /&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;This is a functionality of an ideal argument parsing library. Feel free to add your own user story.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-209558491613752787?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/209558491613752787/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2009/12/ideal-options-arguments-parsing-library.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/209558491613752787?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/209558491613752787?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2009/12/ideal-options-arguments-parsing-library.html" title="An ideal options / arguments parsing library for Python" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DkUNRX08cSp7ImA9WxJbF0U.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-8595573837849883844</id><published>2009-07-28T05:13:00.000-07:00</published><updated>2009-07-28T05:31:34.379-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-28T05:31:34.379-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="subprocess" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Subprocessing. Why it won't be truly crossplatfrom</title><content type="html">Every language and application stops to be crossplatform when it comes to executing other applications. Differences in a way various operating systems execute applications is so inconvenient that even new Python Subprocess API is not complete to keep you isolated from them.&lt;br /&gt;&lt;br /&gt;Suppose you have an executable script.py in &lt;span style="font-weight:bold;"&gt;current directory&lt;/span&gt; that you want to execute. You would definitely need to execute the script through shell, because only shell knows which program should process it.&lt;br /&gt;&lt;br /&gt;Windows&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;subprocess.Popen("script.py",shell=True)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;POSIX&lt;br /&gt;&lt;code class="prettyprint"&gt;&lt;br /&gt;subprocess.Popen("./script.py",shell=True)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So you still need to keep in mind that to &lt;span style="font-weight:bold;"&gt;execute script from current directory&lt;/span&gt; you need to prefix the script with &lt;span style="font-weight:bold;"&gt;./&lt;/span&gt; under POSIX.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-8595573837849883844?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/8595573837849883844/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2009/07/subprocessing-why-it-wont-be-truly.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8595573837849883844?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8595573837849883844?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2009/07/subprocessing-why-it-wont-be-truly.html" title="Subprocessing. Why it won't be truly crossplatfrom" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0MDRXs6eyp7ImA9WxJVE0s.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-8413718399912072802</id><published>2009-06-30T05:11:00.000-07:00</published><updated>2009-06-30T06:44:34.513-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-30T06:44:34.513-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="network" /><category scheme="http://www.blogger.com/atom/ns#" term="debian" /><category scheme="http://www.blogger.com/atom/ns#" term="virtualbox" /><title>Lost network interfaces after moving Debian virtualbox to another host</title><content type="html">Every time Debian virtual machine migrates to a new host, it loses its network interfaces. Debian guest detects new virtual hardware and assigns new aliases losing IP address and other settings. The easiest way is to rename new interface back to original way by editing &lt;a href="http://blog.dhampir.no/content/where-to-rename-network-interfaces-in-debian-etch"&gt;hard to find&lt;/a&gt; config file &lt;span style="font-weight:bold;"&gt;/etc/udev/rules.d/z25_persistent-net.rules&lt;/span&gt; (works for etch)&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;sudo vim /etc/udev/rules.d/z25_persistent-net.rules&lt;/code&gt;&lt;br /&gt;Do not forget to check actual settings for network interfaces with&lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;sudo ifconfig -a&lt;/code&gt;&lt;br /&gt;and settings that are applied on each restart in &lt;br /&gt;&lt;br /&gt;&lt;code class="prettyprint"&gt;sudo vim /etc/network/interfaces&lt;/code&gt;&lt;br /&gt;Instead of renaming network interfaces in Debian it might be easier to record MAC numbers in Notes for virtual machine and setup virtual network interfaces in host accordingly prior to starting imported machine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-8413718399912072802?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/8413718399912072802/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2009/06/lost-network-interfaces-after-moving.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8413718399912072802?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/8413718399912072802?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2009/06/lost-network-interfaces-after-moving.html" title="Lost network interfaces after moving Debian virtualbox to another host" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUQDQ3w6fyp7ImA9WxJWE0U.&quot;"><id>tag:blogger.com,1999:blog-1623059707500976008.post-1037579674377694680</id><published>2009-06-18T08:17:00.000-07:00</published><updated>2009-06-18T21:56:12.217-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T21:56:12.217-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Note about using "App paths" for installers</title><content type="html">&lt;span style="font-weight:bold;"&gt;App paths&lt;/span&gt; is &lt;a href="http://msdn.microsoft.com/en-us/library/cc144150(VS.85).aspx#app_paths"&gt;recommended&lt;/a&gt; (or better say - preferred) way to register application in Windows since Windows XP Service Pack 1 (SP1). I've got a box with Windows XP Home Edition SP3 and I would like to say that from user/application experience it is a bad recommendation and there are two reasons why &lt;span style="font-weight:bold;"&gt;App Paths is evil&lt;/span&gt;.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;&lt;span style="font-style:italic;"&gt;cmd&lt;/span&gt; environment doesn't understand &lt;span style="font-weight:bold;"&gt;App Paths&lt;/span&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;span style="font-weight:bold;"&gt;App Paths&lt;/span&gt; seems to work only if application installed for All Users, i.e. &lt;span style="font-weight:bold;"&gt;App Paths&lt;/span&gt; keys created in HKEY_CURRENT_USER are ignored by the system and only those added to HKEY_LOCAL_MACHINE work.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I was surprised to see &lt;span style="font-style:italic;"&gt;Inkscape.exe&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;Python.exe&lt;/span&gt; entries under &lt;span style="font-style:italic;"&gt;HKCU&lt;/span&gt;. &lt;a href="http://python.org"&gt;Python&lt;/a&gt; didn't work from &lt;span style="font-style:italic;"&gt;Start-&gt;Run dialog (Win-R)&lt;/span&gt; until I moved it to &lt;span style="font-style:italic;"&gt;HKLM&lt;/span&gt;. &lt;a href="http://www.inkscape.org/"&gt;Inkscape&lt;/a&gt; had entries in both &lt;span style="font-style:italic;"&gt;HKCU&lt;/span&gt; &lt;span style="font-weight:bold;"&gt;App Paths&lt;/span&gt; and in &lt;span style="font-style:italic;"&gt;HKLM&lt;/span&gt;, so it worked right away, but the set of fields in both was different, so I assumed it stores some valuable user-specific information there. Frankly speaking I was even more surprised to find out that &lt;a href="http://python.org"&gt;Python&lt;/a&gt; works under &lt;a href="http://farmanager.com"&gt;Far Manager&lt;/a&gt; even if its &lt;span style="font-weight:bold;"&gt;App Paths&lt;/span&gt; setting located in &lt;span style="font-style:italic;"&gt;HKCU&lt;/span&gt;, but it is because Far checks this key itself explicitly. I do not know if it is good assuming that system itself doesn't check this key.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1623059707500976008-1037579674377694680?l=techtonik.rainforce.org' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://techtonik.rainforce.org/feeds/1037579674377694680/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://techtonik.rainforce.org/2009/06/note-about-using-app-paths-for.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1037579674377694680?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1623059707500976008/posts/default/1037579674377694680?v=2" /><link rel="alternate" type="text/html" href="http://techtonik.rainforce.org/2009/06/note-about-using-app-paths-for.html" title="Note about using &quot;App paths&quot; for installers" /><author><name>anatoly techtonik</name><uri>https://profiles.google.com/110592708597698994191</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-7aZLGcpl-zQ/AAAAAAAAAAI/AAAAAAAAAAA/2DiBG26LgA0/s512-c/photo.jpg" /></author><thr:total>0</thr:total></entry></feed>

