<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
   >
  <title type="text">Code Kills</title>
  <subtitle type="text"></subtitle>

  <updated>2013-06-17T17:33:35Z</updated>
  <generator uri="http://blogofile.com/">Blogofile</generator>

  <link rel="alternate" type="text/html" href="http://blog.codekills.net" />
  <id>http://blog.codekills.net/feed/atom/</id>
  <link rel="self" type="application/atom+xml" href="http://blog.codekills.net/feed/atom/" />
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">strftime: table of locale-aware formatters in different locales</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2013/04/13/strftime--table-of-locale-aware-formatters-in-different-locales" />
    <id>http://blog.codekills.net/2013/04/13/strftime--table-of-locale-aware-formatters-in-different-locales</id>
    <updated>2013-04-14T02:44:20Z</updated>
    <published>2013-04-14T02:44:20Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">strftime: table of locale-aware formatters in different locales</summary>
    <content type="html" xml:base="http://blog.codekills.net/2013/04/13/strftime--table-of-locale-aware-formatters-in-different-locales">

&lt;p&gt;
  I got curious about what the different locale-specific strftime and strptime
  formatting directives produced in different locales&amp;hellip; So I built a
  little script which would genreate a table showing each of the different
  locale-aware formatters in all of the different locales which I&#39;ve got
  installed!
&lt;/p&gt;

&lt;p&gt;
  The code used to generate this table can be found at:
  &lt;a href=&#34;https://bitbucket.org/wolever/locale-table&#34;&gt;bitbucket.org/wolever/locale-table&lt;/a&gt;.
&lt;/p&gt;

&lt;style&gt;
td, th {
    padding-left: 10px;
    padding-right: 10px;
}

thead th {
    text-align: left;
}
tbody th {
    text-align: right;
}
tbody td {
    font-family: monospace;
}
tbody tr:nth-child(odd) {
    background-color: rgba(0, 0, 0, 0.10);
}
&lt;/style&gt;

&lt;table cellspacing=&#39;0&#39;&gt;
&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;
&lt;th&gt;%a&lt;/th&gt;
&lt;th&gt;%A&lt;/th&gt;
&lt;th&gt;%b&lt;/th&gt;
&lt;th&gt;%B&lt;/th&gt;
&lt;th&gt;%x&lt;/th&gt;
&lt;th&gt;%X&lt;/th&gt;
&lt;th&gt;%p&lt;/th&gt;
&lt;th&gt;%c&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;af_ZA&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;08/16/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;Tue Aug 16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;am_ET&lt;/th&gt;
&lt;td&gt;ማክሰ&lt;/td&gt;
&lt;td&gt;ማክሰኞ&lt;/td&gt;
&lt;td&gt;ኦገስ&lt;/td&gt;
&lt;td&gt;ኦገስት&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;ማክሰ ኦገስ 16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;be_BY&lt;/th&gt;
&lt;td&gt;аў &lt;/td&gt;
&lt;td&gt;аўторак&lt;/td&gt;
&lt;td&gt;жні&lt;/td&gt;
&lt;td&gt;жніўня&lt;/td&gt;
&lt;td&gt;16.08.88&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;аў  16 жні 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;bg_BG&lt;/th&gt;
&lt;td&gt;Вт &lt;/td&gt;
&lt;td&gt;Вторник&lt;/td&gt;
&lt;td&gt;Авг&lt;/td&gt;
&lt;td&gt;Август&lt;/td&gt;
&lt;td&gt;16.08.88&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Вт  16 Авг 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;ca_ES&lt;/th&gt;
&lt;td&gt;dim&lt;/td&gt;
&lt;td&gt;dimarts&lt;/td&gt;
&lt;td&gt;ago&lt;/td&gt;
&lt;td&gt;agost&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;dim 16 ago 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;cs_CZ&lt;/th&gt;
&lt;td&gt;út&lt;/td&gt;
&lt;td&gt;úterý&lt;/td&gt;
&lt;td&gt;srp&lt;/td&gt;
&lt;td&gt;srpna&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;od&lt;/td&gt;
&lt;td&gt;út 16 srp 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;da_DK&lt;/th&gt;
&lt;td&gt;Tir&lt;/td&gt;
&lt;td&gt;Tirsdag&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tir 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;de_AT&lt;/th&gt;
&lt;td&gt;Di&lt;/td&gt;
&lt;td&gt;Dienstag&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Di 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;de_CH&lt;/th&gt;
&lt;td&gt;Di&lt;/td&gt;
&lt;td&gt;Dienstag&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Di 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;de_DE&lt;/th&gt;
&lt;td&gt;Di&lt;/td&gt;
&lt;td&gt;Dienstag&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Di 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;el_GR&lt;/th&gt;
&lt;td&gt;Τρι&lt;/td&gt;
&lt;td&gt;Τρίτη&lt;/td&gt;
&lt;td&gt;Αυγ&lt;/td&gt;
&lt;td&gt;Αυγούστου&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;μμ&lt;/td&gt;
&lt;td&gt;Τρι 16 Αυγ 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;en_AU&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tue 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;en_CA&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tue 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;en_GB&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tue 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;en_IE&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tue 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;en_NZ&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tue 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;en_US&lt;/th&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Tuesday&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;08/16/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;Tue Aug 16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;es_ES&lt;/th&gt;
&lt;td&gt;mar&lt;/td&gt;
&lt;td&gt;martes&lt;/td&gt;
&lt;td&gt;ago&lt;/td&gt;
&lt;td&gt;agosto&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;mar 16 ago 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;et_EE&lt;/th&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;teisipäev&lt;/td&gt;
&lt;td&gt;aug  &lt;/td&gt;
&lt;td&gt;august&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;T, 16. aug   1988. 21:30:05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;eu_ES&lt;/th&gt;
&lt;td&gt;as.&lt;/td&gt;
&lt;td&gt;asteartea&lt;/td&gt;
&lt;td&gt;Abu&lt;/td&gt;
&lt;td&gt;abuztua&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;p.m.&lt;/td&gt;
&lt;td&gt;1988 - Abu - 16 as. 21:30:05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;fi_FI&lt;/th&gt;
&lt;td&gt;Ti&lt;/td&gt;
&lt;td&gt;Tiistai&lt;/td&gt;
&lt;td&gt;Elo&lt;/td&gt;
&lt;td&gt;Elokuu&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Ti 16 Elo 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;fr_BE&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Mardi&lt;/td&gt;
&lt;td&gt;aoû&lt;/td&gt;
&lt;td&gt;août&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Mar 16 aoû 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;fr_CA&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Mardi&lt;/td&gt;
&lt;td&gt;aoû&lt;/td&gt;
&lt;td&gt;août&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Mar 16 aoû 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;fr_CH&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Mardi&lt;/td&gt;
&lt;td&gt;aoû&lt;/td&gt;
&lt;td&gt;août&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Mar 16 aoû 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;fr_FR&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Mardi&lt;/td&gt;
&lt;td&gt;aoû&lt;/td&gt;
&lt;td&gt;août&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Mar 16 aoû 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;he_IL&lt;/th&gt;
&lt;td&gt;ג&#39;&lt;/td&gt;
&lt;td&gt;שלישי&lt;/td&gt;
&lt;td&gt;אוג&lt;/td&gt;
&lt;td&gt;אוגוסט&lt;/td&gt;
&lt;td&gt;16/08/88&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt; 21:30:05 1988 אוג 16 ג&#39;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;hr_HR&lt;/th&gt;
&lt;td&gt;Ut&lt;/td&gt;
&lt;td&gt;Utorak&lt;/td&gt;
&lt;td&gt;Kol&lt;/td&gt;
&lt;td&gt;Kolovoz&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Ut 16 Kol 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;hu_HU&lt;/th&gt;
&lt;td&gt;Ked&lt;/td&gt;
&lt;td&gt;Kedd&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;Augusztus&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;du&lt;/td&gt;
&lt;td&gt;Ked Aug 16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;hy_AM&lt;/th&gt;
&lt;td&gt;Երք&lt;/td&gt;
&lt;td&gt;Երեքշաբթի&lt;/td&gt;
&lt;td&gt;Օգս&lt;/td&gt;
&lt;td&gt;Օգոստոս&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Երեքշաբթի, 16 Օգոստոս 1988 ի. 21:30:05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;is_IS&lt;/th&gt;
&lt;td&gt;þri&lt;/td&gt;
&lt;td&gt;þriðjudagur&lt;/td&gt;
&lt;td&gt;ágú&lt;/td&gt;
&lt;td&gt;ágúst&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;eh&lt;/td&gt;
&lt;td&gt;þri 16 ágú 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;it_CH&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Martedì&lt;/td&gt;
&lt;td&gt;Ago&lt;/td&gt;
&lt;td&gt;Agosto&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Mar 16 Ago 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;it_IT&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Martedì&lt;/td&gt;
&lt;td&gt;Ago&lt;/td&gt;
&lt;td&gt;Agosto&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Mar 16 Ago 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;ja_JP&lt;/th&gt;
&lt;td&gt;火&lt;/td&gt;
&lt;td&gt;火曜日&lt;/td&gt;
&lt;td&gt; 8&lt;/td&gt;
&lt;td&gt;8月&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21時30分05秒&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;火  8/16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;kk_KZ&lt;/th&gt;
&lt;td&gt;сс&lt;/td&gt;
&lt;td&gt;сейсенбі&lt;/td&gt;
&lt;td&gt;там&lt;/td&gt;
&lt;td&gt;тамыз&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;сейсенбі, 16 тамыз 1988 ж. 21:30:05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;ko_KR&lt;/th&gt;
&lt;td&gt;화&lt;/td&gt;
&lt;td&gt;화요일&lt;/td&gt;
&lt;td&gt; 8&lt;/td&gt;
&lt;td&gt;8월&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21시 30분 05초&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;화  8/16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;lt_LT&lt;/th&gt;
&lt;td&gt;An&lt;/td&gt;
&lt;td&gt;Antradienis&lt;/td&gt;
&lt;td&gt;Rgp&lt;/td&gt;
&lt;td&gt;rugpjūčio&lt;/td&gt;
&lt;td&gt;1988.08.16&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;An Rgp 16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;nl_BE&lt;/th&gt;
&lt;td&gt;di&lt;/td&gt;
&lt;td&gt;dinsdag&lt;/td&gt;
&lt;td&gt;aug&lt;/td&gt;
&lt;td&gt;augustus&lt;/td&gt;
&lt;td&gt;16-08-1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;di 16 aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;nl_NL&lt;/th&gt;
&lt;td&gt;di&lt;/td&gt;
&lt;td&gt;dinsdag&lt;/td&gt;
&lt;td&gt;aug&lt;/td&gt;
&lt;td&gt;augustus&lt;/td&gt;
&lt;td&gt;16-08-1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;di 16 aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;no_NO&lt;/th&gt;
&lt;td&gt;tir&lt;/td&gt;
&lt;td&gt;tirsdag&lt;/td&gt;
&lt;td&gt;aug&lt;/td&gt;
&lt;td&gt;august&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;tir 16 aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;pl_PL&lt;/th&gt;
&lt;td&gt;wto&lt;/td&gt;
&lt;td&gt;wtorek&lt;/td&gt;
&lt;td&gt;sie&lt;/td&gt;
&lt;td&gt;sierpnia&lt;/td&gt;
&lt;td&gt;1988.08.16&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;wto 16 sie 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;pt_BR&lt;/th&gt;
&lt;td&gt;Ter&lt;/td&gt;
&lt;td&gt;Terça Feira&lt;/td&gt;
&lt;td&gt;Ago&lt;/td&gt;
&lt;td&gt;Agosto&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Ter 16 Ago 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;pt_PT&lt;/th&gt;
&lt;td&gt;Ter&lt;/td&gt;
&lt;td&gt;Terça Feira&lt;/td&gt;
&lt;td&gt;Ago&lt;/td&gt;
&lt;td&gt;Agosto&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Ter 16 Ago 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;ro_RO&lt;/th&gt;
&lt;td&gt;Mar&lt;/td&gt;
&lt;td&gt;Marţi&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;August&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Mar 16 Aug 1988 21:30:05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;ru_RU&lt;/th&gt;
&lt;td&gt;вт&lt;/td&gt;
&lt;td&gt;вторник&lt;/td&gt;
&lt;td&gt;авг&lt;/td&gt;
&lt;td&gt;августа&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;вторник, 16 августа 1988 г. 21:30:05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;sk_SK&lt;/th&gt;
&lt;td&gt;ut &lt;/td&gt;
&lt;td&gt;utorok&lt;/td&gt;
&lt;td&gt;aug&lt;/td&gt;
&lt;td&gt;august&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;ut  16 aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;sl_SI&lt;/th&gt;
&lt;td&gt;tor&lt;/td&gt;
&lt;td&gt;torek&lt;/td&gt;
&lt;td&gt;avg&lt;/td&gt;
&lt;td&gt;avgust&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;tor 16 avg 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;sr_YU&lt;/th&gt;
&lt;td&gt;уто&lt;/td&gt;
&lt;td&gt;уторак&lt;/td&gt;
&lt;td&gt;авг&lt;/td&gt;
&lt;td&gt;август&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;уто 16 авг 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;sv_SE&lt;/th&gt;
&lt;td&gt;Tis&lt;/td&gt;
&lt;td&gt;Tisdag&lt;/td&gt;
&lt;td&gt;Aug&lt;/td&gt;
&lt;td&gt;Augusti&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;pm&lt;/td&gt;
&lt;td&gt;Tis 16 Aug 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;tr_TR&lt;/th&gt;
&lt;td&gt;Sal&lt;/td&gt;
&lt;td&gt;Salı&lt;/td&gt;
&lt;td&gt;Ağu&lt;/td&gt;
&lt;td&gt;Ağustos&lt;/td&gt;
&lt;td&gt;16/08/1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;PM&lt;/td&gt;
&lt;td&gt;Sal 16 Ağu 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;uk_UA&lt;/th&gt;
&lt;td&gt;вт&lt;/td&gt;
&lt;td&gt;вівторок&lt;/td&gt;
&lt;td&gt;сер&lt;/td&gt;
&lt;td&gt;серпня&lt;/td&gt;
&lt;td&gt;16.08.1988&lt;/td&gt;
&lt;td&gt;21:30:05&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;вт 16 сер 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;zh_CN&lt;/th&gt;
&lt;td&gt;二&lt;/td&gt;
&lt;td&gt;星期二&lt;/td&gt;
&lt;td&gt; 8&lt;/td&gt;
&lt;td&gt;八月&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21时30分05秒&lt;/td&gt;
&lt;td&gt;下午&lt;/td&gt;
&lt;td&gt;二  8/16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;zh_HK&lt;/th&gt;
&lt;td&gt;二&lt;/td&gt;
&lt;td&gt;周二&lt;/td&gt;
&lt;td&gt; 8&lt;/td&gt;
&lt;td&gt;8月&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21時30分05秒&lt;/td&gt;
&lt;td&gt;下午&lt;/td&gt;
&lt;td&gt;二  8/16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;zh_TW&lt;/th&gt;
&lt;td&gt;二&lt;/td&gt;
&lt;td&gt;周二&lt;/td&gt;
&lt;td&gt; 8&lt;/td&gt;
&lt;td&gt;8月&lt;/td&gt;
&lt;td&gt;1988/08/16&lt;/td&gt;
&lt;td&gt;21時30分05秒&lt;/td&gt;
&lt;td&gt;下午&lt;/td&gt;
&lt;td&gt;二  8/16 21:30:05 1988&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">South&#39;s frozen models are big liars</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2013/03/07/south's-frozen-models-are-big-liars" />
    <id>http://blog.codekills.net/2013/03/07/south's-frozen-models-are-big-liars</id>
    <updated>2013-03-07T19:53:46Z</updated>
    <published>2013-03-07T19:53:46Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <category scheme="http://blog.codekills.net" term="Django" />
    <summary type="html">South&#39;s frozen models are big liars</summary>
    <content type="html" xml:base="http://blog.codekills.net/2013/03/07/south's-frozen-models-are-big-liars">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;Consider South&#39;s &lt;tt class=&#34;docutils literal&#34;&gt;orm&lt;/tt&gt; object,
&lt;a class=&#34;reference external&#34; href=&#34;http://south.readthedocs.org/en/latest/ormfreezing.html&#34;&gt;http://south.readthedocs.org/en/latest/ormfreezing.html&lt;/a&gt;, which provides
&amp;quot;frozen-in-time&amp;quot; versions of ORM models:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
(Pdb++) from my_app.models import MyModel
(Pdb++) MyModel
&amp;lt;class &#39;my_app.models.MyModel&#39;&amp;gt;
(Pdb++) orm[&#39;my_app.MyModel&#39;]
&amp;lt;class &#39;my_app.models.MyModel&#39;&amp;gt;
(Pdb++) orm[&#39;my_app.MyModel&#39;] == MyModel
False
&lt;/pre&gt;
&lt;p&gt;Notice that the magic South frozen model appears to be in the same namespace
as my real model: &lt;tt class=&#34;docutils literal&#34;&gt;my_app.models&lt;/tt&gt;!&lt;/p&gt;
&lt;p&gt;This is at best stupid, and at worst potentially dangerous.&lt;/p&gt;
&lt;p&gt;It makes perfect sense that South needs some mechanism for providing
&amp;quot;frozen models&amp;quot; (ie, which match the database schema at the time of migration,
of the current schema), but they are emphatically &lt;em&gt;not&lt;/em&gt; the same as the real
models (don&#39;t have any of the real methods, etc), so it should be made &lt;em&gt;very
clear&lt;/em&gt; that they are different! There are many ways this could be done, but one
very simple step would be putting them in a different namespace, which makes it
clear that these models are frozen, and references the migrations they belong
to:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
(Pdb++) orm[&#39;my_app.MyModel&#39;]
&amp;lt;class &#39;south.frozen_models.my_app.models_0003.MyModel&#39;&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Additionally, this is a bad code smell which could potentially lead to bugs:
because the &amp;quot;frozen model class&amp;quot; is lying about where it&#39;s from, any
code which relies on the module path will do surprising things. In fact, it&#39;s
such a big problem that pickle explicitly checks for this case:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
(Pdb++) import pickle
(Pdb++) pickle.dumps(orm[&#39;my_app.MyModel&#39;])
*** PicklingError: Can&#39;t pickle &amp;lt;class &#39;my_app.models.MyModel&#39;&amp;gt;:
    it&#39;s not the same object as my_app.models.MyModel
&lt;/pre&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Anti-Pattern: Duck typing with try/except</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2012/11/29/anti-pattern--duck-typing-with-try-except" />
    <id>http://blog.codekills.net/2012/11/29/anti-pattern--duck-typing-with-try-except</id>
    <updated>2012-11-29T23:46:19Z</updated>
    <published>2012-11-29T23:46:19Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">Anti-Pattern: Duck typing with try/except</summary>
    <content type="html" xml:base="http://blog.codekills.net/2012/11/29/anti-pattern--duck-typing-with-try-except">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;An anti-pattern I&#39;ve often seen is using try/except incorrectly in an attempt
at duck typing:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
try:
    widget.frob()
except AttibuteError:
    # widget can&#39;t be frobbed
    do_something_else()
&lt;/pre&gt;
&lt;p&gt;This is fundamentally broken because it will conceal bugs in the
&lt;tt class=&#34;docutils literal&#34;&gt;widget.frob()&lt;/tt&gt; method (ie, if there&#39;s a bug in &lt;tt class=&#34;docutils literal&#34;&gt;widget.frob()&lt;/tt&gt; which
causes an &lt;tt class=&#34;docutils literal&#34;&gt;AttibuteError&lt;/tt&gt; to be raised).&lt;/p&gt;
&lt;p&gt;In this situation, the only safe way to use try/except would be:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
try:
    widget_frob = widget.frob
except AttibuteError:
    # widget can&#39;t be frobbed
    do_something_else()
else:
    widget_frob()
&lt;/pre&gt;
&lt;p&gt;This ensures that bugs in &lt;tt class=&#34;docutils literal&#34;&gt;widget.frob()&lt;/tt&gt; won&#39;t be accidentally hidden.&lt;/p&gt;
&lt;p&gt;Of course, this code is no where near as pretty as the &amp;quot;incorrect&amp;quot; version,
which is why I&#39;ve come to believe that using try/except for duck typing could
be considered an anti-pattern, and that &lt;tt class=&#34;docutils literal&#34;&gt;hasattr&lt;/tt&gt; is generally preferable
(except in situations where performance is important, as try/except will almost
certainly be faster):&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
if hasattr(widget, &amp;quot;frob&amp;quot;):
    widget.frob()
else:
    # widget can&#39;t be frobbed
    do_something_else()
&lt;/pre&gt;
&lt;p&gt;And of course, all this goes without saying that a naked &lt;tt class=&#34;docutils literal&#34;&gt;except:&lt;/tt&gt; is &lt;em&gt;always&lt;/em&gt;
&lt;a class=&#34;reference external&#34; href=&#34;http://blog.codekills.net/2011/09/29/the-evils-of--except--/&#34;&gt;an absolutely terrible idea&lt;/a&gt;...&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">The evils of `except:`</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/09/29/the-evils-of--except--" />
    <id>http://blog.codekills.net/2011/09/29/the-evils-of--except--</id>
    <updated>2011-09-29T19:34:24Z</updated>
    <published>2011-09-29T19:34:24Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">The evils of `except:`</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/09/29/the-evils-of--except--">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;I had some discussion recently about the evils of using a naked &lt;tt class=&#34;docutils literal&#34;&gt;except:&lt;/tt&gt;.
Here is a more complete description of the dangers, and of the correct
solutions.&lt;/p&gt;
&lt;p&gt;In short, &lt;tt class=&#34;docutils literal&#34;&gt;except:&lt;/tt&gt; is bad because hides the source source of the exception
and frustrates debugging.  For example, consider this code:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
try:
    parsed = parse(file_name)
except:
    raise ParseError(&amp;quot;can&#39;t parse file&amp;quot;)
&lt;/pre&gt;
&lt;p&gt;It will likely produce an error something like this:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
$ ./my_program.py
Traceback (most recent call last):
    ...
ParseError: can&#39;t parse file
&lt;/pre&gt;
&lt;p&gt;This kind of error makes me want to high-five someone. In the face. With a
chair.&lt;/p&gt;
&lt;p&gt;Notice that it does not contain &lt;em&gt;any&lt;/em&gt; information about:&lt;/p&gt;
&lt;ul class=&#34;simple&#34;&gt;
&lt;li&gt;The file which caused the error&lt;/li&gt;
&lt;li&gt;The line which caused the error&lt;/li&gt;
&lt;li&gt;The nature of the error (is it an expected error? A bug? Who knows!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And tracking down the source of this error would likely involve some binary
searching on the input file or dropping into a debugger.&lt;/p&gt;
&lt;p&gt;These are some other, equally unhelpful, bits of code that I have seen:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
# There isn&#39;t much worse than completely hiding the error
except:
    pass

# Almost as bad is not giving any hit at what it was
except:
    print &amp;quot;there was an error!&amp;quot;

# And even showing the original error can be unhelpful if the error is
# something like an IndexError which could come from anywhere
except Exception, e:
    raise MyException(&amp;quot;there was an error: %r&amp;quot; %(e, ))
&lt;/pre&gt;
&lt;p&gt;Now, there &lt;em&gt;is&lt;/em&gt; a situations where using a naked &lt;tt class=&#34;docutils literal&#34;&gt;except:&lt;/tt&gt; can be used
safely. Exactly one.&lt;/p&gt;
&lt;div class=&#34;section&#34; id=&#34;the-except-block-is-terminated-with-a-raise&#34;&gt;
&lt;h1&gt;1. The &lt;tt class=&#34;docutils literal&#34;&gt;except:&lt;/tt&gt; block is terminated with a &lt;tt class=&#34;docutils literal&#34;&gt;raise&lt;/tt&gt;&lt;/h1&gt;
&lt;p&gt;For example, when some cleanup needs to be done before leaving the function:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
cxn = open_connection()
try:
    use_connection(cxn)
except:
    close_connection(cxn)
    raise
&lt;/pre&gt;
&lt;p&gt;(note that, usually, the &lt;tt class=&#34;docutils literal&#34;&gt;finally:&lt;/tt&gt; block should be used for this kind of
cleanup, but there are some situations where the code above makes more sense)&lt;/p&gt;
&lt;p&gt;Every other situation should use &lt;tt class=&#34;docutils literal&#34;&gt;except Exception, e:&lt;/tt&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;section&#34; id=&#34;a-new-exception-is-raised-but-the-original-stack-trace-is-used&#34;&gt;
&lt;h1&gt;2. A new exception is raised but the original stack trace is used&lt;/h1&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
try:
    parsed = parse(file_name)
except Exception, e:
    raise ParseError(&amp;quot;error parsing %r: %r&amp;quot; %(file_name, e)), None, sys.exc_info()[2]
&lt;/pre&gt;
&lt;p&gt;A few things to note: first, the &lt;a class=&#34;reference external&#34; href=&#34;http://docs.python.org/reference/simple_stmts.html#grammar-token-raise_stmt&#34;&gt;three expression&lt;/a&gt;
version of &lt;tt class=&#34;docutils literal&#34;&gt;raise&lt;/tt&gt; is used, the third of which being the current stack trace.
This means that the stack trace will point to the &lt;em&gt;original source&lt;/em&gt; of the
error:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
File &amp;quot;my_program.py&amp;quot;, line 9, in &amp;lt;module&amp;gt;
  parse(file_name)
File &amp;quot;parser.py&amp;quot;, line 2, in parse
  for lineno, line in enumerate(open(file_name), &amp;quot;rb&amp;quot;):
ParseError: error parsing &#39;input.bin&#39;: TypeError(&amp;quot;&#39;str&#39; object cannot be interpreted as an index&amp;quot;,)
&lt;/pre&gt;
&lt;p&gt;Instead of the (less helpful) line which re-raised the error:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
File &amp;quot;my_program.py&amp;quot;, line 11, in &amp;lt;module&amp;gt;
  raise ParseError(&amp;quot;error parsing %r: %r&amp;quot; %(file_name, e))
ParseError: error parsing &#39;input.bin&#39;: TypeError(&amp;quot;&#39;str&#39; object cannot be interpreted as an index&amp;quot;,)
&lt;/pre&gt;
&lt;p&gt;Second, the error includes the file name and original exception, which will
make debugging significantly easier. When I&#39;m writing particularly fragile code
I&#39;ll often wrap the entire block in a try/except which will include as much
state as is sensible in the error. For example, the main loop of the &lt;tt class=&#34;docutils literal&#34;&gt;parse&lt;/tt&gt;
function might be:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
def parse(file_name):
    lineno = -1
    current_foo = None
    try:
        f = open(file_name)
        for lineno, line in enumerate(f):
            current_foo = line.split()[0]
            ...
    except Exception, e:
        raise ParseError(&amp;quot;error while parsing %r (line %r; current_foo: %r): %r&amp;quot;
                         %(file_name, lineno, current_foo, e)), None, sys.exc_info()[2]
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&#34;section&#34; id=&#34;the-exception-and-stack-trace-are-logged&#34;&gt;
&lt;h1&gt;3. The exception and stack trace are logged&lt;/h1&gt;
&lt;p&gt;For example, the main runloop of an application might be:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
while 1:
    try:
        do_stuff()
    except Exception, e:
        log.exception(&amp;quot;error in mainloop&amp;quot;)
        time.sleep(1)
&lt;/pre&gt;
&lt;p&gt;A few things to note: first, a naked &lt;tt class=&#34;docutils literal&#34;&gt;except:&lt;/tt&gt; should &lt;em&gt;not&lt;/em&gt; be used here, as
it will also catch &lt;tt class=&#34;docutils literal&#34;&gt;KeyboardInterrupt&lt;/tt&gt; and &lt;tt class=&#34;docutils literal&#34;&gt;SystemExit&lt;/tt&gt; exceptions, which
is almost certainly a bad thing.&lt;/p&gt;
&lt;p&gt;Second, &lt;tt class=&#34;docutils literal&#34;&gt;log.exception&lt;/tt&gt; is used, which includes a complete stack trace in the
log (care should also be taken to make sure that these logs will be checked -
for example by sending an email on exception logs).&lt;/p&gt;
&lt;p&gt;Third, the &lt;tt class=&#34;docutils literal&#34;&gt;time.sleep(1)&lt;/tt&gt; ensures that the system won&#39;t get clobbered if the
&lt;tt class=&#34;docutils literal&#34;&gt;do_stuff()&lt;/tt&gt; function immediately raises an exception.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Checking types in Python</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/09/26/checking-types-in-python" />
    <id>http://blog.codekills.net/2011/09/26/checking-types-in-python</id>
    <updated>2011-09-26T17:53:08Z</updated>
    <published>2011-09-26T17:53:08Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">Checking types in Python</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/09/26/checking-types-in-python">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;A friend asked me recently when it&#39;s acceptable to check types in Python. Here
is my reply:&lt;/p&gt;
&lt;p&gt;It is almost never a good idea to check that function arguments are exactly the
type you expect. For example, these two functions are very, very bad:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
def add(a, b):
    if not isinstance(a, int):
        raise ValueError(&amp;quot;a is not an int&amp;quot;)
    if not isinstance(b, int):
        raise ValueError(&amp;quot;b is not an int&amp;quot;)
    return a + b

def sum(xs):
    if not isinstance(xs, list):
        raise ValueError(&amp;quot;xs is not a list&amp;quot;)
    base = 0
    for x in xs:
        base += x
    return base
&lt;/pre&gt;
&lt;p&gt;There&#39;s no reason to impose those restrictions, and it makes life difficult if,
for example, you want to add floats or sum an iterator:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
&amp;gt;&amp;gt;&amp;gt; add(1.2, 3)
...
ValueError(&amp;quot;a is not an int&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; sum(person.age for person in people)
...
ValueError(&amp;quot;xs is not a list&amp;quot;)
&lt;/pre&gt;
&lt;p&gt;Type checking to correctly handle different kinds of input is occasionally
acceptable, but should be used carefully (ex, to do optimizations, or
situations where method overloading would be used in other languages). For
example, these functions could be ok:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
def contains_all(haystack, needles):
    if not isinstance(haystack, (set, dict)):
        haystack = set(haystack)
    return all(needle in haystack for needle in needles)

def ping_ip(addr):
    if isinstance(addr, numbers.Number):
        addr = numeric_ip_to_string(addr)
    # ping &#39;addr&#39; which should be a string in &amp;quot;1.2.3.4&amp;quot; form
    ...
&lt;/pre&gt;
&lt;p&gt;But it&#39;s almost always better to check for &lt;em&gt;capabilities&lt;/em&gt; instead of checking for
types. For example, if you want to make sure that &lt;tt class=&#34;docutils literal&#34;&gt;add&lt;/tt&gt; throws an error on
invalid input, this would be a better way:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
def add(a, b):
    if not (hasattr(a, &amp;quot;__add__&amp;quot;) or hasattr(b, &amp;quot;__radd__&amp;quot;)):
        raise ValueError(&amp;quot;can&#39;t add a to b&amp;quot;))
    return a + b
&lt;/pre&gt;
&lt;p&gt;This would be equivalent to excepting an interface instead of an implementation
in a statically typed language:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
// This is equivilent to ``isinstance(xs, list)`` -- usually bad
public static int sum(ArrayList xs) {
    ...
}

// This is equivilent to ``hasattr(xs, &amp;quot;__iter__&amp;quot;)`` -- almost always better
public static int sum(Collection xs) {
    ...
}
&lt;/pre&gt;
&lt;p&gt;Or better yet, Just Do It and wrap any exceptions which pop up:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
def add(a, b):
    try:
        return a + b
    except Exception, e:
        raise ValueError(&amp;quot;cannot add %r and %r: %r&amp;quot; %(a, b, e)), None, sys.exc_info()[2]
&lt;/pre&gt;
&lt;p&gt;In general, though, &lt;em&gt;code should assume that function arguments will behave
correctly&lt;/em&gt;, then let the caller use your documentation and Python&#39;s helpful
stack traces and debugging facilities to figure out what they did wrong.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Python 2.X&#39;s str.format is unsafe</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/09/22/python-2.x's-str.format-is-unsafe" />
    <id>http://blog.codekills.net/2011/09/22/python-2.x's-str.format-is-unsafe</id>
    <updated>2011-09-22T23:33:00Z</updated>
    <published>2011-09-22T23:33:00Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <category scheme="http://blog.codekills.net" term="Unicode" />
    <summary type="html">Python 2.X&#39;s str.format is unsafe</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/09/22/python-2.x's-str.format-is-unsafe">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;I posted &lt;a class=&#34;reference external&#34; href=&#34;http://twitter.com/wolever/status/116966636606603264&#34;&gt;a tweet&lt;/a&gt;
today when I learned that Python&#39;s %-string-formatting isn&#39;t actually a special
case - the &lt;tt class=&#34;docutils literal&#34;&gt;str&lt;/tt&gt; class just implements the &lt;tt class=&#34;docutils literal&#34;&gt;__mod__&lt;/tt&gt; method.&lt;/p&gt;
&lt;p&gt;One side effect of this is that a few people commented that %-formatting is to
be replaced with &lt;tt class=&#34;docutils literal&#34;&gt;.format&lt;/tt&gt; formatting... So I&#39;d like to take this opportunity
to explain why &lt;tt class=&#34;docutils literal&#34;&gt;.format&lt;/tt&gt; string formatting &lt;strong&gt;is unsafe&lt;/strong&gt; in Python 2.X.&lt;/p&gt;
&lt;p&gt;With %-formatting, if the format string is a &lt;tt class=&#34;docutils literal&#34;&gt;str&lt;/tt&gt; while one of the
replacements is a &lt;tt class=&#34;docutils literal&#34;&gt;unicode&lt;/tt&gt; the result will be &lt;tt class=&#34;docutils literal&#34;&gt;unicode&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;quot;Hello %s&amp;quot; %(u&amp;quot;world&amp;quot;, )
u&#39;Hello world&#39;
&lt;/pre&gt;
&lt;p&gt;However, &lt;tt class=&#34;docutils literal&#34;&gt;.format&lt;/tt&gt; will always return the same type of string (&lt;tt class=&#34;docutils literal&#34;&gt;str&lt;/tt&gt; or
&lt;tt class=&#34;docutils literal&#34;&gt;unicode&lt;/tt&gt;) as the format string:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;quot;Hello {}&amp;quot;.format(u&amp;quot;world&amp;quot;)
&#39;Hello world&#39;
&lt;/pre&gt;
&lt;p&gt;This is a problem in Python 2.X because unqualified string literals are
instances of &lt;tt class=&#34;docutils literal&#34;&gt;str&lt;/tt&gt;, and the implicit encoding of &lt;tt class=&#34;docutils literal&#34;&gt;unicode&lt;/tt&gt; arguments will
almost certainly explode at the least opportune moments:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;quot;Hello {}&amp;quot;.format(u&amp;quot;\u263a&amp;quot;)
Traceback (most recent call last):
  File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
UnicodeEncodeError: &#39;ascii&#39; codec can&#39;t encode character u&#39;\u263a&#39; in position 0: ordinal not in range(128)
&lt;/pre&gt;
&lt;p&gt;Of course, one possible solution to this is remembering to prefix all string
literals with &lt;tt class=&#34;docutils literal&#34;&gt;u&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
&amp;gt;&amp;gt;&amp;gt; u&amp;quot;Hello {}&amp;quot;.format(u&amp;quot;\u263a&amp;quot;)
u&#39;Hello \u263a&#39;
&lt;/pre&gt;
&lt;p&gt;But I prefer to simply use %-style formatting, because then I don&#39;t need to
remember anything:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;quot;Hello %s&amp;quot; %(u&amp;quot;\u263a&amp;quot;, )
u&#39;Hello \u263a&#39;
&amp;gt;&amp;gt;&amp;gt; print _.encode(&#39;utf-8&#39;)
Hello ☺
&lt;/pre&gt;
&lt;p&gt;Of course, as you&#39;ve probably noticed, this means that the format string is
being implicitly decoded to unicode... But since my string literals generally
don&#39;t contain non-ASCII characters it&#39;s not much of an issue.&lt;/p&gt;
&lt;p&gt;Note that this is &lt;strong&gt;not&lt;/strong&gt; a problem in Py 3k because string literals are
&lt;tt class=&#34;docutils literal&#34;&gt;unicode&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Lies, More Lies and Python Packaging Documentation on `package_data`</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/07/15/lies,-more-lies-and-python-packaging-documentation-on--package_data-" />
    <id>http://blog.codekills.net/2011/07/15/lies,-more-lies-and-python-packaging-documentation-on--package_data-</id>
    <updated>2011-07-16T00:35:18Z</updated>
    <published>2011-07-16T00:35:18Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">Lies, More Lies and Python Packaging Documentation on `package_data`</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/07/15/lies,-more-lies-and-python-packaging-documentation-on--package_data-">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;My slice of Python packaging hell today was thanks to the lie that is
&lt;tt class=&#34;docutils literal&#34;&gt;package_data&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;You see, I&#39;ve been trying to create an package that includes non-Python files
in the distribution... So I did what any good developer would do and hit the
documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Package data can be added to packages using the package_data keyword
argument to the setup() function.&lt;/p&gt;
&lt;p class=&#34;attribution&#34;&gt;&amp;mdash;&lt;a class=&#34;reference external&#34; href=&#34;http://docs.python.org/distutils/setupscript.html#installing-package-data&#34;&gt;Distutils documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you want finer-grained control over what files are included (for
example, if you have documentation files in your package directories and
want to exclude them from installation), then you can also use the
&lt;tt class=&#34;docutils literal&#34;&gt;package_data&lt;/tt&gt; keyword.&lt;/p&gt;
&lt;p class=&#34;attribution&#34;&gt;&amp;mdash;&lt;a class=&#34;reference external&#34; href=&#34;http://packages.python.org/distribute/setuptools.html#including-data-files&#34;&gt;Distribute documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the last hour, though, I&#39;ve learned that these statements are somewhere
between “dangerously misleading” and “damn lies”.&lt;/p&gt;
&lt;p&gt;This is because the primary type of Python package is a source package, and the
canonical method for creating a source package is by using &lt;tt class=&#34;docutils literal&#34;&gt;setup.py sdist&lt;/tt&gt;.
However, the data specified in &lt;tt class=&#34;docutils literal&#34;&gt;package_data&lt;/tt&gt; are &lt;strong&gt;not&lt;/strong&gt; included in source
distributions — they are &lt;strong&gt;only&lt;/strong&gt; included in binary (&lt;tt class=&#34;docutils literal&#34;&gt;setup.py bdist&lt;/tt&gt;)
distributions and installs (&lt;tt class=&#34;docutils literal&#34;&gt;setup.py install&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;The only way to get package data included in source packages is the
&lt;tt class=&#34;docutils literal&#34;&gt;MANIFEST.in&lt;/tt&gt; file... Which will &lt;strong&gt;also&lt;/strong&gt; include data in binary
distributions and installs.&lt;/p&gt;
&lt;p&gt;Which renders the &lt;tt class=&#34;docutils literal&#34;&gt;package_data&lt;/tt&gt; option useful only if &lt;tt class=&#34;docutils literal&#34;&gt;sdist&lt;/tt&gt; is not used…
And dangerously misleading if &lt;tt class=&#34;docutils literal&#34;&gt;sdist&lt;/tt&gt; is used.&lt;/p&gt;
&lt;p&gt;tl;dr: &lt;tt class=&#34;docutils literal&#34;&gt;package_data&lt;/tt&gt; is a lie. Ignore it. Only use &lt;tt class=&#34;docutils literal&#34;&gt;MANIFEST.in&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Tips for Managing a Django Project</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/06/22/tips-for-managing-a-django-project" />
    <id>http://blog.codekills.net/2011/06/22/tips-for-managing-a-django-project</id>
    <updated>2011-06-22T20:44:05Z</updated>
    <published>2011-06-22T20:44:05Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <category scheme="http://blog.codekills.net" term="Django" />
    <summary type="html">Tips for Managing a Django Project</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/06/22/tips-for-managing-a-django-project">&lt;div class=&#34;document&#34;&gt;
&lt;p&gt;During the time I&#39;ve spent with Django, I&#39;ve picked up a couple tricks for
making life a little bit less terrible.&lt;/p&gt;
&lt;p&gt;First, split the project project into three (or more) parts, each with its own
&lt;tt class=&#34;docutils literal&#34;&gt;settings.py&lt;/tt&gt;: the main project, the development environment and the
production environment. For example, my current project, code named &lt;tt class=&#34;docutils literal&#34;&gt;eos&lt;/tt&gt;,
has a directory structure something like this:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
eos/
    .hg/
    .hgignore
    manage.py
    run
    eos/
        __init__.py
        settings.py
        templates/
        urls.py
        ...
    hacking/
        __init__.py
        settings.py
        db.sqlite3
        ...
    production/
        __init__.py
        settings.py
        run.wsgi
    ...
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class=&#34;docutils literal&#34;&gt;eos/&lt;/tt&gt; directory is more or less a standard Django project (ie, created
by &lt;tt class=&#34;docutils literal&#34;&gt;&lt;span class=&#34;pre&#34;&gt;django-admin.py&lt;/span&gt; startproject&lt;/tt&gt;), except that &lt;tt class=&#34;docutils literal&#34;&gt;eos/settings.py&lt;/tt&gt; does not
have any environment-specific information in it (for example, it doesn&#39;t have
any database settings or URLs).&lt;/p&gt;
&lt;p&gt;The &lt;tt class=&#34;docutils literal&#34;&gt;hacking/&lt;/tt&gt; and &lt;tt class=&#34;docutils literal&#34;&gt;production/&lt;/tt&gt; directories also contain &lt;tt class=&#34;docutils literal&#34;&gt;settings.py&lt;/tt&gt;
files, except they define &lt;strong&gt;only&lt;/strong&gt; environment specific settings. For example,
&lt;tt class=&#34;docutils literal&#34;&gt;hacking/settings.py&lt;/tt&gt; looks a bit like this:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
from eos.settings import *
path = lambda *parts: os.path.join(os.path.dirname(__file__), *parts)

DATABASE_ENGINE = &amp;quot;sqlite3&amp;quot;
DATABASE_NAME = path(&amp;quot;db.sqlite3&amp;quot;)

DEBUG = True
&lt;/pre&gt;
&lt;p&gt;While &lt;tt class=&#34;docutils literal&#34;&gt;production/settings.py&lt;/tt&gt; contains:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
from eos.settings import *

DATABASE_ENGINE = &amp;quot;psycopg2&amp;quot;
DATABASE_NAME = &amp;quot;eos&amp;quot;
DATABASE_USER = &amp;quot;eos&amp;quot;
DATABASE_PASSWORD = &amp;quot;secret&amp;quot;

DEBUG = False
&lt;/pre&gt;
&lt;p&gt;Then, instead of configuring Django (ie, calling &lt;tt class=&#34;docutils literal&#34;&gt;setup_environment&lt;/tt&gt;) on
&lt;tt class=&#34;docutils literal&#34;&gt;eos.settings&lt;/tt&gt;, it is called on either &lt;tt class=&#34;docutils literal&#34;&gt;hacking.settings&lt;/tt&gt; or
&lt;tt class=&#34;docutils literal&#34;&gt;production.settings&lt;/tt&gt;. For example, &lt;tt class=&#34;docutils literal&#34;&gt;manage.py&lt;/tt&gt; contains:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
...
import hacking.settings
execute_manager(hacking.settings)
&lt;/pre&gt;
&lt;p&gt;And &lt;tt class=&#34;docutils literal&#34;&gt;production/run.wsgi&lt;/tt&gt; contains:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
...
os.environ[&amp;quot;DJANGO_SETTINGS_MODULE&amp;quot;] = &amp;quot;production.settings&amp;quot;
...
&lt;/pre&gt;
&lt;p&gt;Second, every &lt;tt class=&#34;docutils literal&#34;&gt;settings.py&lt;/tt&gt; file should contain the &lt;tt class=&#34;docutils literal&#34;&gt;path&lt;/tt&gt; lambda:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
path = lambda *parts: os.path.join(os.path.dirname(__file__), *parts)
&lt;/pre&gt;
&lt;p&gt;It will make specifying paths relative to the &lt;tt class=&#34;docutils literal&#34;&gt;settings.py&lt;/tt&gt; file very easy,
and completely do away with relative-path-related issues. For example:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
MEDIA_ROOT = path(&amp;quot;media/&amp;quot;)
DATA_ROOT = path(&amp;quot;data/&amp;quot;)
DATABASE_NAME = path(&amp;quot;db.sqlite3&amp;quot;)
&lt;/pre&gt;
&lt;p&gt;Third, there should be scripts for running, saving and re-building the
environment. I use two scripts for this: &lt;tt class=&#34;docutils literal&#34;&gt;run&lt;/tt&gt; and &lt;tt class=&#34;docutils literal&#34;&gt;dump_dev_data&lt;/tt&gt;. By
default the &lt;tt class=&#34;docutils literal&#34;&gt;run&lt;/tt&gt; script calls &lt;tt class=&#34;docutils literal&#34;&gt;./manage.py runserver 8631&lt;/tt&gt;
(specifying a port is useful so that web browsers can distinguish between
different applications - keeping passwords, history, etc. separate). Run can
also be passed a &lt;tt class=&#34;docutils literal&#34;&gt;reset&lt;/tt&gt; argument, which will delete the development database
and rebuild it from the &lt;tt class=&#34;docutils literal&#34;&gt;dev&lt;/tt&gt; fixtures. These fixtures are created by the
&lt;tt class=&#34;docutils literal&#34;&gt;dump_dev_data&lt;/tt&gt; script, which calls &lt;tt class=&#34;docutils literal&#34;&gt;./manage.py dumpdata&lt;/tt&gt; for each
application, saving the data to fixtures named &lt;tt class=&#34;docutils literal&#34;&gt;dev&lt;/tt&gt; (these fixtures are
committed along side the code, so all developers can work off the same data).&lt;/p&gt;
&lt;p&gt;So, for example, when I&#39;m developing a new model, my workflow will look
something like this:&lt;/p&gt;
&lt;pre class=&#34;literal-block&#34;&gt;
... add new model to models.py ...
$ ./run reset # Reset the database adding the new model
... use the website to create data for the new model ...
$ ./dump_dev_data # Dump the newly created data
$ hg commit -m &amp;quot;Adding new model + test data&amp;quot;
&lt;/pre&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <author>
      <name>David Wolever</name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Python security tip: urllib/urllib2 will read `file://` URLs</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/06/05/python-security-tip--urllib-urllib2-will-read--file-----urls" />
    <id>http://blog.codekills.net/2011/06/05/python-security-tip--urllib-urllib2-will-read--file-----urls</id>
    <updated>2011-06-06T03:03:00Z</updated>
    <published>2011-06-06T03:03:00Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">Python security tip: urllib/urllib2 will read `file://` URLs</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/06/05/python-security-tip--urllib-urllib2-will-read--file-----urls">

&lt;p&gt;I discovered, entirely by accident, that &lt;code&gt;urllib2.urlopen&lt;/code&gt;, &lt;code&gt;urllib.urlretrieve&lt;/code&gt;, and probably others, will happily read &lt;code&gt;file://&lt;/code&gt; urls and filesystem paths. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import urllib, urllib2
&amp;gt;&amp;gt;&amp;gt; urllib.urlretrieve(&#34;database_connection_settings.txt&#34;, &#34;/tmp/temp_file&#34;)
(&#39;/tmp/temp_file&#39;, &amp;lt;mimetools.Message instance at 0x…&amp;gt;)
&amp;gt;&amp;gt;&amp;gt; urllib2.urlopen(&#34;file:///dev/urandom&#34;).read(10)
&#39;\xf1r?\x0fC\x86p\x05\xa4\xdd&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that applications which blindly &lt;code&gt;urlopen&lt;/code&gt; untrusted URLs (for example, from RSS feeds) are potentially vulnerable to information disclosure and denial of service attacks.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <author>
      <name>David Wolever</name>
      <uri>http://blog.codekills.net</uri>
    </author>
    <title type="html">Bug caused by Python&#39;s significant whitespace</title>
    <link rel="alternate" type="text/html" href="http://blog.codekills.net/2011/05/25/bug-caused-by-python's-significant-whitespace" />
    <id>http://blog.codekills.net/2011/05/25/bug-caused-by-python's-significant-whitespace</id>
    <updated>2011-05-25T19:12:00Z</updated>
    <published>2011-05-25T19:12:00Z</published>
    <category scheme="http://blog.codekills.net" term="Python" />
    <summary type="html">Bug caused by Python&#39;s significant whitespace</summary>
    <content type="html" xml:base="http://blog.codekills.net/2011/05/25/bug-caused-by-python's-significant-whitespace">

&lt;p&gt;I encountered my first bug (in recent memory) that was caused by Python&#39;s significant whitespace today.&lt;/p&gt;
&lt;p&gt;As I was editing a class, I accidentally left-shifted an entire method, effectively removing the rest of the methods from the class:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Foo:
    def foo(self):
        …

def accidentally_shifted_left(self):
    …

    def bar(self):
        …
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
</feed>
