<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    <title>Code Kills - Python</title>
    <link>http://blog.codekills.net/</link>
    <description></description>
    <dc:language>en</dc:language>
    <admin:errorReportsTo rdf:resource="mailto:david@wolever.net" />
    <generator>Serendipity 1.1.3 - http://www.s9y.org/</generator>
    <pubDate>Fri, 19 Feb 2010 20:35:09 GMT</pubDate>

    <image>
        <url>http://blog.codekills.net/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: Code Kills - Python - </title>
        <link>http://blog.codekills.net/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>Absolute paths must die</title>
    <link>http://blog.codekills.net/archives/80-Absolute-paths-must-die.html</link>
            <category>Python</category>
    
    <comments>http://blog.codekills.net/archives/80-Absolute-paths-must-die.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=80</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=80</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;Ok guys, it&#039;s pretty simple: if you&#039;re working in a Turing-complete environment and you&#039;ve got paths which start with a &#039;/&#039;, you&#039;re doing it wrong. &lt;strong&gt;Very wrong!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Todays offender: &lt;a href=&quot;http://www.wsgi.org/wsgi/&quot;&gt;WSGI&lt;/a&gt; scripts.&lt;/p&gt;

&lt;p&gt;Here&#039;s the first line of a common WSGI script:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;app_path = &#039;/path/to/application&#039;&lt;/pre&gt;

&lt;p&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;See a problem there? That&#039;s right, the &lt;strong&gt;absolute path&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;How could this be solved? Simple: put the WSGI script &lt;em&gt;in&lt;/em&gt; &lt;code&gt;/path/to/application&lt;/code&gt;, then get the &lt;code&gt;app_path&lt;/code&gt; using: &lt;code&gt;app_path=os.path.abspath(os.path.dirname(__file__))&lt;/code&gt;. Problem solved.&lt;/p&gt;

&lt;p&gt;&amp;lt;/rant&gt;&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Sat, 13 Feb 2010 17:23:22 -0500</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/80-guid.html</guid>
    
</item>
<item>
    <title>Django settings.py mini-tip: the `path` lambda</title>
    <link>http://blog.codekills.net/archives/74-Django-settings.py-mini-tip-the-path-lambda.html</link>
            <category>Python</category>
    
    <comments>http://blog.codekills.net/archives/74-Django-settings.py-mini-tip-the-path-lambda.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=74</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=74</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;There are a few things I do every time I start a new Django site, and one of those things is add my &lt;code&gt;path&lt;/code&gt; lambda to the top of settings.py:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    import os
    ROOT = os.path.abspath(os.path.dirname(__file__))
    path = lambda *args: os.path.join(ROOT, *args)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From then on, it&#039;s drop-dead simple to create absolute paths which are relative to the root of the project (or, at least, the directory which contains settings.py). For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    &gt;&gt;&gt; path(&#039;media/&#039;)
    &#039;/Users/wolever/code/review_anywhere/media/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And some other places where it is useful:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    DATABASE_ENGINE = &#039;sqlite3&#039;
    DATABASE_NAME = path(&#039;db.sqlite3&#039;)
    ...
    TEMPLATE_DIRS = (
        path(&#039;templates/&#039;),
    )
    ...
    DATA_DIR = path(&#039;data/&#039;)
    ...
&lt;/code&gt;&lt;/pre&gt;
 
    </content:encoded>

    <pubDate>Sun, 17 Jan 2010 22:26:41 -0500</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/74-guid.html</guid>
    
</item>
<item>
    <title>str(...): 'yer probably doin' it wrong.</title>
    <link>http://blog.codekills.net/archives/45-str...-yer-probably-doin-it-wrong..html</link>
            <category>Python</category>
            <category>Unicode</category>
    
    <comments>http://blog.codekills.net/archives/45-str...-yer-probably-doin-it-wrong..html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=45</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=45</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;Unicode is an ugly beast... And until people start standardizing on Python 3k*,
we&#039;re going to have to live with the eccentricities of Python 2&#039;s strings.&lt;/p&gt;

&lt;p&gt;But, fear not! There is (at least some) hope. By changing a few patterns in the
way you code, you can alleviate the bulk of Unicode-related problems.&lt;/p&gt;

&lt;p&gt;First, using the &lt;tt&gt;str&lt;/tt&gt; function.  In just about every case, if you&#039;re
using the &lt;tt&gt;str&lt;/tt&gt; function, you&#039;re probably doing it wrong.&lt;/p&gt;

&lt;p&gt;Let me demonstrate:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from hashlib import sha256
def hash(to_hash):
  hash = sha256(to_hash).hexdigest()
  print to_hash, &quot;:&quot;, hash
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool, we can hash things then print out the hash:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; hash(&#039;ohai&#039;)
ohai : e84712238709398f6d349dc2250b0efca4b72d8c2bfb7b74339d30ba94056b14
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But, wait... What happens if the thing we&#039;re hashing isn&#039;t a string (even though
it can be represented as a string):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; class Person:
...   name = &#039;David&#039;
...   def __str__(self):
...     return self.name
...
&amp;gt;&amp;gt;&amp;gt; hash(Person())
...
TypeError: new() argument 1 must be string or read-only buffer, not instance
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oh no!  Ok, let&#039;s fix the code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from hashlib import sha256
def hash(to_hash):
  to_hash = str(to_hash) # Convert the object to a string before we hash it
  hash = sha256(to_hash).hexdigest()
  print to_hash, &quot;:&quot;, hash
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Great -- we can hash numbers now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; hash(Person())
David : a6b54c20a7b96eeac1a911e6da3124a560fe6dc042ebf270e3676e7095b95652
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And, for most people who only speak English, this is a perfect place to stop.
After all, everything is a &lt;code&gt;str&lt;/code&gt;, right?&lt;/p&gt;

&lt;p&gt;Well... No.  What happens if the input is a &lt;code&gt;unicode&lt;/code&gt; object?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; p = Person()
&amp;gt;&amp;gt;&amp;gt; # This person had the audacity to give themselves a name containing
&amp;gt;&amp;gt;&amp;gt; # non-ascii symbols, so we represent it with a unicode object
&amp;gt;&amp;gt;&amp;gt; p.name = u&#039;I\xf1t\xebrn\xe2ti\xf4n\xe0liz\xe6ti\xf8n&#039;
&amp;gt;&amp;gt;&amp;gt; hash(p)
...
UnicodeEncodeError: &#039;ascii&#039; codec can&#039;t encode character u&#039;\xf1&#039; in position
1: ordinal not in range(128)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Crap.  Where the heck is &#039;ascii&#039; coming from?&lt;/p&gt;

&lt;p&gt;Well, it&#039;s a long story (which I&#039;ve covered over at &lt;a href=&quot;http://blog.codekills.net/archives/38-Encoding-and-Decoding-Text-in-Python-or-I-didnt-ask-you-to-use-the-ascii-codec!.html&quot;&gt;Encoding and Decoding Text
in
Python&lt;/a&gt;),
but basically the &lt;code&gt;__str__&lt;/code&gt; method of the unicode object (u&#039;I\xf1...&#039;) is trying to
encode the unicode object using the system&#039;s default encoding... Which, in this
case, is ascii.&lt;/p&gt;

&lt;p&gt;&quot;Alright...&quot;, you&#039;re probably thinking, &quot;If the problem is with &lt;code&gt;unicode&lt;/code&gt;, maybe
I could just replace that call to &lt;code&gt;str&lt;/code&gt; with a call to &lt;code&gt;unicode&lt;/code&gt;&quot;&lt;/p&gt;

&lt;p&gt;Ok, let&#039;s see what happens.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from hashlib import sha256
def hash(to_hash):
  to_hash = unicode(to_hash) # Convert the object to a unicode before we hash it
  hash = sha256(to_hash).hexdigest()
  print to_hash, &quot;:&quot;, hash

&amp;gt;&amp;gt;&amp;gt; # this time, though, the person&#039;s name has come from The Internet, so it
&amp;gt;&amp;gt;&amp;gt; # is not yet a unicode object
&amp;gt;&amp;gt;&amp;gt; p.name = &#039;I\xc3\xb1t\xc3\xabrn\xc3\xa2ti\xc3\xb4n\xc3\xa0liz\xc3\xa6ti\xc3\xb8n&#039;
&amp;gt;&amp;gt;&amp;gt; hash(p)
...
UnicodeDecodeError: &#039;ascii&#039; codec can&#039;t decode byte 0xc3 in position 1:
ordinal not in range(128)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yup, that&#039;s right -- you just can&#039;t win &lt;img src=&quot;http://blog.codekills.net/templates/default/img/emoticons/sad.png&quot; alt=&quot;:-(&quot; style=&quot;display: inline; vertical-align: bottom;&quot; class=&quot;emoticon&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What&#039;s happening here?  Well, this time, the &lt;code&gt;unicode&lt;/code&gt; function is trying to
decode the input (&#039;I\xc3...&#039;) into a unicode object... But, because the input
isn&#039;t valid 7-bit ascii (again, the system&#039;s default), it explodes. Crap.&lt;/p&gt;

&lt;p&gt;Confused yet?&lt;/p&gt;

&lt;p&gt;So how can we save ourselves from all this insanity?&lt;/p&gt;

&lt;p&gt;Actually, it&#039;s not too difficult:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Convert every single string, with out exception, to unicode as soon as they
enter the system.  For example, if you are writing a web application,
GET and POST variables should be converted to &lt;code&gt;unicode&lt;/code&gt; as soon as they are
read from the environment:&lt;/p&gt;

&lt;p&gt;for (key, value) in environment.get_vars:
    request.GET[to_unicode(key)] = to_unicode(value)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only convert the &lt;code&gt;unicode&lt;/code&gt; objects back to &lt;code&gt;str&lt;/code&gt; strings when you absolutly
must.  For example, when they are written to a file:&lt;/p&gt;

&lt;p&gt;log_file.write(&quot;New user &#039;%s&#039; created&quot; %(to_str(p.name)))&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Think hard before you call &lt;code&gt;str&lt;/code&gt; or &lt;code&gt;unicode&lt;/code&gt;. Each time your fingers type
&quot;s&quot;, &quot;t&quot;, flashing lights and sirens should go off in your head, reminding
you to make sure that the object you are &lt;code&gt;str&lt;/code&gt;ing could never, ever, ever
possibly contain unicode.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And what about those &lt;code&gt;to_unicode&lt;/code&gt; and &lt;code&gt;to_str&lt;/code&gt; functions?  What should they look
like?  Well, probably something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import locale
def to_unicode(text):
    &quot;&quot;&quot; Convert, at all consts, &#039;text&#039; to a `unicode` object.

        Note: as a last-ditch effort, this function tries to decode the text
              as latin1... Which will always succeed.  If you expect to get
              text encoded with latin[2-9] or some other character set, this
              may not be desierable.

        &amp;gt;&amp;gt;&amp;gt; to_unicode(u&#039;I\xf1t\xebrn\xe2ti&#039;)
        u&#039;I\xf1t\xebrn\xe2ti&#039;
        &amp;gt;&amp;gt;&amp;gt; to_unicode(&#039;I\xc3\xb1t\xc3\xabrn\xc3\xa2ti&#039;)
        u&#039;I\xf1t\xebrn\xe2ti&#039;
        &amp;gt;&amp;gt;&amp;gt; class Foo:
        ...   def __str__(self):
        ...       return &#039;foo&#039;
        ...
        &amp;gt;&amp;gt;&amp;gt; f = Foo()
        &amp;gt;&amp;gt;&amp;gt; to_unicode(f)
        u&#039;foo&#039;
        &amp;gt;&amp;gt;&amp;gt; f.__unicode__ = u&#039;bar&#039;
        &amp;gt;&amp;gt;&amp;gt; to_unicode(f)
        u&#039;bar&#039;
        &amp;gt;&amp;gt;&amp;gt; &quot;&quot;&quot;

    if isinstance(text, unicode):
        return text

    if hasattr(text, &#039;__unicode__&#039;):
        return text.__unicode__()

    text = str(text)

    try:
        return unicode(text, &#039;utf-8&#039;)
    except UnicodeError:
        pass

    try:
        return unicode(text, locale.getpreferredencoding())
    except UnicodeError:
        pass

    return unicode(text, &#039;latin1&#039;)


def to_str(text):
    &quot;&quot;&quot; Convert &#039;text&#039; to a `str` object.

        &amp;gt;&amp;gt;&amp;gt; to_str(u&#039;I\xf1t\xebrn\xe2ti&#039;)
        &#039;I\xc3\xb1t\xc3\xabrn\xc3\xa2ti&#039;
        &amp;gt;&amp;gt;&amp;gt; to_str(42)
        &#039;42&#039;
        &amp;gt;&amp;gt;&amp;gt; to_str(&#039;ohai&#039;)
        &#039;ohai&#039;
        &amp;gt;&amp;gt;&amp;gt; class Foo:
        ...     def __str__(self):
        ...         return &#039;foo&#039;
        ...
        &amp;gt;&amp;gt;&amp;gt; f = Foo()
        &amp;gt;&amp;gt;&amp;gt; to_str()
        &#039;foo&#039;
        &amp;gt;&amp;gt;&amp;gt; f.__unicode__ = lambda: u&#039;I\xf1t\xebrn\xe2ti&#039;
        &amp;gt;&amp;gt;&amp;gt; to_str(f)
        &#039;I\xc3\xb1t\xc3\xabrn\xc3\xa2ti&#039;
        &amp;gt;&amp;gt;&amp;gt; &quot;&quot;&quot;
    if isinstance(text, str):
        return text

    if hasattr(text, &#039;__unicode__&#039;):
        text = text.__unicode__()

    if hasattr(text, &#039;__str__&#039;):
        return text.__str__()

    return text.encode(&#039;utf-8&#039;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So there you have it.
A quick and fairly easy way to avoid many of your encoding-related options &lt;img src=&quot;http://blog.codekills.net/templates/default/img/emoticons/smile.png&quot; alt=&quot;:-)&quot; style=&quot;display: inline; vertical-align: bottom;&quot; class=&quot;emoticon&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you&#039;re still not quite feeling comfortable with all of this, though, take a
read over &lt;a href=&quot;http://www.joelonsoftware.com/articles/Unicode.html&quot;&gt;Joel Spolsky&#039;s The Absolute Minimum Every Software Developer
Absolutely, Positively Must Know About Unicode and Character Sets (No
Excuses!)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;*: My newly installed Debian 4 machine is still running Python 2.4 (released
December 2004)... So that wait might be a while.&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Tue, 10 Feb 2009 11:13:19 -0500</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/45-guid.html</guid>
    
</item>
<item>
    <title>Python Brain-Teaser</title>
    <link>http://blog.codekills.net/archives/41-Python-Brain-Teaser.html</link>
            <category>Play</category>
            <category>Python</category>
    
    <comments>http://blog.codekills.net/archives/41-Python-Brain-Teaser.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=41</wfw:comment>

    <slash:comments>3</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=41</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;I&#039;m working on pulling some functionality out of one object and putting it in another, and I came across this interesting problem:&lt;/p&gt;

&lt;p&gt;&lt;style type=&quot;text/css&quot;&gt;
/**
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 */
.python .de1, .python .de2 {color: #000060; font-weight: normal;}
.python  {white-space: nowrap;border: 1px dotted #a0a0a0; font-family: &#039;Courier New&#039;, Courier, monospace; font-size: 110%; background-color: #f0f0f0; margin: 0; line-height: 110%; padding: 0;color: #000099;}
.python a:link {color: #006;}
.python a:hover {background-color: #d6d6e6;}
.python .head {font-family: Verdana, Arial, sans-serif; color: #808080; font-size: 70%; font-weight: bold; background-color: #f0f0ff; border-bottom: 1px solid #d0d0d0; padding: 2px;}
.python .foot {font-family: Verdana, Arial, sans-serif; color: #808080; font-size: 70%; font-weight: bold; background-color: #f0f0ff; border-top: 1px solid #d0d0d0; padding: 2px;}
.python .imp {font-weight: bold; color: red;}
.python li, .python li.li1 {font-family: &#039;Courier New&#039;, Courier, monospace; color: #000060; background-color: #e0e0e0; padding-bottom: 2px;}
.python .kw1 {color: #ff7700;font-weight:bold;}
.python .kw2 {color: #008000;}
.python .kw3 {color: #dc143c;}
.python .kw4 {color: #0000cd;}
.python .co1 {color: #808080; font-style: italic;}
.python .coMULTI {color: #808080; font-style: italic;}
.python .es0 {color: #000099; font-weight: bold;font-weight: normal;}
.python .br0 {color: black;}
.python .sy0 {color: #66cc66;}
.python .st0 {color: #483d8b;}
.python .nu0 {color: #ff4500;}
.python .me1 {color: black;}
.python .me {1}
&lt;/style&gt;&lt;/p&gt;

&lt;div class=&quot;python&quot;&gt;
&lt;div class=&quot;de1&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;class&lt;/span&gt; Foo:&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160; &amp;#160; me = &lt;span class=&quot;st0&quot;&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;class&lt;/span&gt; Bar:&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160; &amp;#160; me = &lt;span class=&quot;st0&quot;&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160; &amp;#160; &lt;span class=&quot;kw1&quot;&gt;def&lt;/span&gt; get_me&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;:&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &lt;span class=&quot;kw1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;me1&quot;&gt;me&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;Foo.&lt;span class=&quot;me1&quot;&gt;get_me&lt;/span&gt; = Bar.&lt;span class=&quot;me1&quot;&gt;get_me&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;x = Foo&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&amp;#160;&lt;/div&gt;
&lt;div class=&quot;de1&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;print&lt;/span&gt; x.&lt;span class=&quot;me1&quot;&gt;get_me&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;What does this print?&lt;/p&gt;

&lt;p&gt;And, next question, why is that?&lt;/p&gt;

&lt;p&gt;After lunch I&#039;ll post my thoughts &lt;img src=&quot;http://blog.codekills.net/templates/default/img/emoticons/smile.png&quot; alt=&quot;:-)&quot; style=&quot;display: inline; vertical-align: bottom;&quot; class=&quot;emoticon&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;
 &lt;br /&gt;&lt;a href=&quot;http://blog.codekills.net/archives/41-Python-Brain-Teaser.html#extended&quot;&gt;Continue reading &quot;Python Brain-Teaser&quot;&lt;/a&gt;
    </content:encoded>

    <pubDate>Thu, 29 May 2008 11:14:57 -0400</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/41-guid.html</guid>
    
</item>
<item>
    <title>SSH and HTTPS on the same port?!</title>
    <link>http://blog.codekills.net/archives/36-SSH-and-HTTPS-on-the-same-port!.html</link>
            <category>Play</category>
            <category>Python</category>
    
    <comments>http://blog.codekills.net/archives/36-SSH-and-HTTPS-on-the-same-port!.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=36</wfw:comment>

    <slash:comments>3</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=36</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;A friend of mine was over the other night, and we were talking about how much we like running SSH on port 443.  It gets you around all but the most insane firewalls, and to anyone but the keenest of observers it just looks like HTTPS traffic.&lt;/p&gt;

&lt;p&gt;But running SSH over port 443 makes it particularly difficult to run a secure web server as well.&lt;/p&gt;

&lt;p&gt;So what can be done?&lt;/p&gt;

&lt;p&gt;Well, it turns out that when an SSH client initiates a connection, it waits for the server to send a banner (&lt;code&gt;SSH-1.99-OpenSSH_4.7&lt;/code&gt;, for example) before beginning the secure negotiation.  Browsers, on the other hand, just go right ahead and begin the secure negotiation.&lt;/p&gt;

&lt;p&gt;Knowing this, it didn&#039;t take long to formulate a plan: write a little program which will listen on 443.  When it gets a connection, it figures out if the remote end is trying to speak SSH or HTTPS, makes the appropriate connection on the local end, the passes the data between the two.&lt;/p&gt;

&lt;p&gt;It only took a couple of hours to write a &lt;a href=&quot;http://wolever.net/~wolever/sstp/sstp.py&quot;&gt;small proof-of-concept&lt;/a&gt;... And, believe it or not, it even works! &lt;small&gt;Disclaimer: this particular implementation is not quite suitable for any real use.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Anyway, this may not be the most efficient way of doing things... But that&#039;s no matter.  It&#039;s still neat &lt;img src=&quot;http://blog.codekills.net/templates/default/img/emoticons/smile.png&quot; alt=&quot;:-)&quot; style=&quot;display: inline; vertical-align: bottom;&quot; class=&quot;emoticon&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Code: &lt;a href=&quot;http://wolever.net/~wolever/sstp/sstp.py&quot;&gt;sstp.py&lt;/a&gt;&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Fri, 11 Apr 2008 17:38:16 -0400</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/36-guid.html</guid>
    
</item>
<item>
    <title>Reverting Changes in SVN (or: it's not as easy as svn up -r)</title>
    <link>http://blog.codekills.net/archives/33-Reverting-Changes-in-SVN-or-its-not-as-easy-as-svn-up-r.html</link>
            <category>DrProject</category>
            <category>Python</category>
            <category>Work</category>
    
    <comments>http://blog.codekills.net/archives/33-Reverting-Changes-in-SVN-or-its-not-as-easy-as-svn-up-r.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=33</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=33</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;If there is one thing that I&#039;ve found universally confusing about version control systems, it&#039;s how to revert back to a previous revision, then move on from there.  Conventional wisdom would dictate that &lt;code&gt;svn up -r $OLD&lt;/code&gt; with some additional flag that says &lt;code&gt;pretend that we&#039;re still at HEAD&lt;/code&gt; would do the trick... But, alas, there exists no such flag.&lt;/p&gt;

&lt;p&gt;So, besides &lt;code&gt;svn cat -r $OLD $FILE &amp;gt; $FILE&lt;/code&gt;, what&#039;s the best way to revert a file (or entire tree) to an older revision?  Well, it turns out that &lt;strong&gt;merge&lt;/strong&gt; is the tool you&#039;re looking for.&lt;/p&gt;

&lt;p&gt;The trick is that you can &lt;code&gt;diff&lt;/code&gt; backwards as well as forwards:&lt;/p&gt;

&lt;pre&gt;
[wolever@thebes] ~/test_dr/All svn diff -r &lt;strong&gt;2:1&lt;/strong&gt;
Index: stuff
===================================================================
--- stuff       (revision 2)
+++ stuff       (revision 1)
@@ -1,4 +1,3 @@
 Let us endeavor so to live that when we come to die even the undertaker will be
 sorry.
                -- Mark Twain, &quot;Pudd&#039;nhead Wilson&#039;s Calendar&quot;
-Increased knowledge will help you now.  Have mate&#039;s phone bugged.
Index: docs.html
&lt;/pre&gt;

&lt;p&gt;Which means that &lt;strong&gt;merge&lt;/strong&gt; will work both ways as well:&lt;/p&gt;

&lt;pre&gt;
[wolever@thebes] ~/test_dr/All svn &lt;strong&gt;merge -r 2:1&lt;/strong&gt; stuff
U    stuff
[wolever@thebes] ~/test_dr/All svn ci -m &quot;reverted changes&quot; stuff
[wolever@thebes] ~/test_dr/All svn diff -r 1:3 stuff
[wolever@thebes] ~/test_dr/All

&lt;/pre&gt;

&lt;p&gt;Of course, this will also work with the myriad of other version control tools out there.  In fact, if you&#039;re still using SVN, reverting old changes is probably the least of your problems... At least compared to, say, merging different branches ^_^&lt;/p&gt;

&lt;p&gt;But that&#039;s a post for another day -- I need to stop writing about merging and actually get on with, err, &lt;a href=&quot;https://www.drproject.org/DrProject/ticket/1236&quot;&gt;doing it&lt;/a&gt;...&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Fri, 08 Feb 2008 11:57:24 -0500</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/33-guid.html</guid>
    
</item>
<item>
    <title>Amazon S3 (or, How I Solved My Image Hosting Woes)</title>
    <link>http://blog.codekills.net/archives/11-Amazon-S3-or,-How-I-Solved-My-Image-Hosting-Woes.html</link>
            <category>Play</category>
            <category>Python</category>
    
    <comments>http://blog.codekills.net/archives/11-Amazon-S3-or,-How-I-Solved-My-Image-Hosting-Woes.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=11</wfw:comment>

    <slash:comments>6</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=11</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;A couple months ago, I read Jeff Atwood&#039;s article on &lt;a href=&quot;http://www.codinghorror.com/blog/archives/000808.html&quot;&gt;Using Amazon S3 as an Image Hosting Service&lt;/a&gt;, but because my favicon does not does not generate &lt;a href=&quot;http://www.hanselman.com/blog/FavIconicoCanBeABandwidthHog.aspx&quot;&gt;27 GBs of traffic a month&lt;/a&gt;, I didn&#039;t think much of it.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;(if you&#039;re scratching your head wondering what &lt;a href=&quot;http://www.amazon.com/gp/browse.html?node=16427261&quot;&gt;Amazon&#039;s S3&lt;/a&gt; is, I&#039;ll do my best to explain.  It stands for Simple Storage Service, and it is just that: a simple service that allows you to store data. That data (or &quot;those files&quot;, if you wish) can be world-readable (from a web browser) or private (many people are &lt;a href=&quot;http://www.google.ca/search?q=amazon+S3+backup&quot;&gt;using it for backup&lt;/a&gt;).  It&#039;s targeted at developers (Amazon only provides a set of APIs -- all GUIs are 3rd party) and it is dirt cheep: only $0.15 a gigabyte.)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Then, a few weeks ago, I was taking some pictures of my sister&#039;s soccer practice, and realized that I needed some place to put them.  After looking at a couple of cheep hosting plans, I decided that I didn&#039;t like them; $5 a month isn&#039;t much, but that&#039;s still $60 a year for a whole lot of space I won&#039;t be using.  Then I remembered S3.&lt;/p&gt;

&lt;p&gt;After a night of playing around, I figured that it should be pretty simple.  Write a script that will go through an HTML file looking for images, then upload them one at a time, replacing the links as it goes. &lt;a href=&quot;http://wolever.net/~wolever/html2s3.py&quot;&gt;html2s3&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;It turns out that the S3 library provided by Amazon is very easy to use, with most of my time spent correcting file paths.  A couple of neat bits:&lt;/p&gt;

&lt;p&gt;&lt;div class=&quot;python&quot; style=&quot;text-align: left&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #dc143c;&quot;&gt;parser&lt;/span&gt; = OptionParser&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;usage = &lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;usage: %prog [options] [FILES]&lt;span style=&quot;color: #000099; font-weight: bold;&quot;&gt;\n&lt;/span&gt;Will process ...&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dc143c;&quot;&gt;parser&lt;/span&gt;.&lt;span style=&quot;color: black;&quot;&gt;add_option&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;-b&quot;&lt;/span&gt;, &lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;--bucket&quot;&lt;/span&gt;, action=&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;store&quot;&lt;/span&gt;, dest=&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;bucket&quot;&lt;/span&gt;, &lt;span style=&quot;color: #008000;&quot;&gt;help&lt;/span&gt;=...&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dc143c;&quot;&gt;parser&lt;/span&gt;.&lt;span style=&quot;color: black;&quot;&gt;add_option&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;-k&quot;&lt;/span&gt;, &lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;--key-prefix&quot;&lt;/span&gt;, dest=&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;remote_base_path&quot;&lt;/span&gt;, &lt;span style=&quot;color: #008000;&quot;&gt;help&lt;/span&gt;=&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;Prefix key ...&quot;&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dc143c;&quot;&gt;parser&lt;/span&gt;.&lt;span style=&quot;color: black;&quot;&gt;add_option&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;-n&quot;&lt;/span&gt;, &lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;--no-backup&quot;&lt;/span&gt;, dest=&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;no_backup&quot;&lt;/span&gt;, action=&lt;span style=&quot;color: #483d8b;&quot;&gt;&quot;store_true&quot;&lt;/span&gt; ...&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;options, args&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt; = &lt;span style=&quot;color: #dc143c;&quot;&gt;parser&lt;/span&gt;.&lt;span style=&quot;color: black;&quot;&gt;parse_args&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;I had seen &lt;code&gt;OptionParser&lt;/code&gt; before, but never used it.  It&#039;s so simple, though, that I think I&#039;m going to use it quite a bit more frequently.&lt;/p&gt;

&lt;p&gt;&lt;div class=&quot;python&quot; style=&quot;text-align: left&quot;&gt;&lt;br /&gt;&amp;#160; source = args &lt;span style=&quot;color: #ff7700;font-weight:bold;&quot;&gt;or&lt;/span&gt; &lt;span style=&quot;color: #dc143c;&quot;&gt;sys&lt;/span&gt;.&lt;span style=&quot;color: black;&quot;&gt;stdin&lt;/span&gt;.&lt;span style=&quot;color: black;&quot;&gt;xreadlines&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160; &lt;span style=&quot;color: #ff7700;font-weight:bold;&quot;&gt;for&lt;/span&gt; line &lt;span style=&quot;color: #ff7700;font-weight:bold;&quot;&gt;in&lt;/span&gt; source:&lt;br /&gt;&amp;#160; &amp;#160; process_entry&lt;span style=&quot;color: black;&quot;&gt;&amp;#40;&lt;/span&gt;line&lt;span style=&quot;color: black;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;One thing I loved about C was the ability to use assignment in loops (&lt;code&gt;while (fgets(buf, sizeof(buf), stdin) != EOF)&lt;/code&gt;), but stdin.xreadlines() does the same sort of thing.&lt;/p&gt;

&lt;p&gt;Update: When I moved the script over to my server, it started telling me that I didn&#039;t have permission to list the bucket.  So I started digging in to it a bit, and found out that I was getting the error &lt;code&gt;RequestTimeTooSkewed&lt;/code&gt;.  It turns out that I forgot to turn my server&#039;s clock back last daylight savings... D&#039;oh!&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Tue, 12 Jun 2007 12:19:42 -0400</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/11-guid.html</guid>
    
</item>
<item>
    <title>Debugging Python</title>
    <link>http://blog.codekills.net/archives/10-Debugging-Python.html</link>
            <category>Python</category>
    
    <comments>http://blog.codekills.net/archives/10-Debugging-Python.html#comments</comments>
    <wfw:comment>http://blog.codekills.net/wfwcomment.php?cid=10</wfw:comment>

    <slash:comments>4</slash:comments>
    <wfw:commentRss>http://blog.codekills.net/rss.php?version=2.0&amp;type=comments&amp;cid=10</wfw:commentRss>
    

    <author>david@wolever.net (David Wolever)</author>
    <content:encoded>
    &lt;p&gt;There are two modules that I use to debug Python code: &lt;code&gt;pdb&lt;/code&gt; and &lt;code&gt;rpdb2&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;pdb&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;There are two main ways that I launch &lt;code&gt;pdb&lt;/code&gt;: from the command line and from a breakpoint within a script.&lt;/p&gt;

&lt;p&gt;To launch pdb from the command line, simply run Python with the &lt;code&gt;-m pdb&lt;/code&gt; flag:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# py -m pdb script name
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(if you&#039;re like me, &lt;code&gt;python&lt;/code&gt; is a bit much to type... A simple fix is to just create a link to the &lt;code&gt;python&lt;/code&gt; binary named &lt;code&gt;py&lt;/code&gt;: &lt;code&gt;ln -s $(which python) /usr/bin/py&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;The second, and much more useful, method of invoking &lt;code&gt;pdb&lt;/code&gt; is the &lt;code&gt;set_trace&lt;/code&gt; function.  To break at any point in your code, simply insert the line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import pdb; pdb.set_trace()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When the code execution gets to that point, it will stop and drop you in to a debugging shell.&lt;br /&gt;
Just to feel cool like the Eclipse kids, I have mapped this to F8 in Vim (&lt;code&gt;map &amp;lt;F8&amp;gt; Oimport pdb; pdb.set_trace() #BREAK&amp;lt;Esc&amp;gt;&lt;/code&gt;)&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;rpdb2&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;rpdb2&lt;/code&gt; stands for Remote Python Debugger 2, and as the name suggests it allows remote debugging. This is useful if &lt;code&gt;pdb&lt;/code&gt; does not play well with the threading/forking in your application (it did not like &lt;a href=&quot;http://webpy.org&quot;&gt;web.py&lt;/a&gt;, for example).  The other, and much greater, benefit of &lt;code&gt;rpdb2&lt;/code&gt; is &lt;a href=&quot;http://www.digitalpeers.com/pythondebugger/&quot;&gt;Winpdb&lt;/a&gt;.  As the name suggests, Winpdb is a graphical Python debugger.&lt;/p&gt;

&lt;p&gt;While Winpdb allows you to run your script from within the application, that is not very helpful if you are working on a beast like &lt;a href=&quot;http://drproject.org&quot;&gt;Drproject&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you&#039;re working with a beastly application, it is much easier to set a &lt;code&gt;rpdb2&lt;/code&gt; breakpoint and then attach Winpdb to the application. To do this, stick this line where ever you want your application to break:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import rpdb2; rpdb2.start_embedded_debugger(&quot;asdf&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When your application gets to that line, it will &quot;hang&quot; as the debugger runs. Now it&#039;s time to fire up Winpdb and attach (File --&gt; Attach) to the process.  The password is &quot;asdf&quot;.  After it loads, you will be able to do debug the application like normal.&lt;/p&gt;

&lt;p&gt;One final note about using &lt;code&gt;rpdb2&lt;/code&gt;: to run a Python command (for instance, in the bottom right window of Winpdb), you have to prefix it with &lt;code&gt;exec&lt;/code&gt; (for instance, &lt;code&gt;exec print foo&lt;/code&gt;).&lt;/p&gt;
 
    </content:encoded>

    <pubDate>Tue, 29 May 2007 14:36:26 -0400</pubDate>
    <guid isPermaLink="false">http://blog.codekills.net/archives/10-guid.html</guid>
    
</item>

</channel>
</rss>