<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>PythonLovers.com</title><link>http://pythonlovers.com/</link><description>Blog aggregator regarding Python</description>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/pythonlovers" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
				<title>People who don't have 100% code coverage are idiots</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/IwxX5JfXloE/people-who-dont-use-code-coverage-are-idiots</link>
				<pubDate>Sun, 22 Feb 2009 23:17:37 GMT</pubDate>
			<description>&lt;div class="document"&gt;
&lt;p&gt;My &lt;a class="reference" href="http://ivory.idyll.org/blog/feb-09/necessity-vs-sufficiency.html"&gt;last post, Good code coverage: Necessity vs Sufficiency&lt;/a&gt;,
about how you should maintain high code coverage with your automated
tests, seems to have really struck a nerve in a small group of people
-- I got some fantastic comments, with some great pointers.  Michael
Foord's comment, 'Too often &amp;quot;testing is no silver bullet&amp;quot; is used as
an excuse not to test' hit the nail on the head, and Andrew Dalke
&lt;a class="reference" href="http://glyph.twistedmatrix.com/2009/02/joel-un-test.html"&gt;linked to his excellent &amp;amp; detailed discussion with Glyph about code
coverage&lt;/a&gt;, as well
as pointing out &lt;a class="reference" href="http://www.sqlite.org/testing.html"&gt;the SQLite testing policy&lt;/a&gt; which is, frankly, astounding.&lt;/p&gt;
&lt;p&gt;But I'm not writing this just to point out those links.  No, this is
partly in response to Ned Batchelder's plaintive question about why I
picked on him.  &lt;strong&gt;I picked on him because of his article's title:
&amp;quot;there are flaws in coverage measurement.&amp;quot;&lt;/strong&gt; Now, Ned is the author of
coverage, the main code coverage tool available for Python -- and I
&lt;em&gt;know&lt;/em&gt; he thinks code coverage is really important.  And it is
entirely legitimate to write critical essays about code coverage,
especially statement coverage. But I also get frustrated with people
who write blog posts with even moderately sensational and
misrepresentative blog post titles.  And that's why I included him in
the post complaining about such things.&lt;/p&gt;
&lt;p&gt;Got that?  &lt;strong&gt;I hate sensational and misrepresentative titles.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Good day.&lt;/p&gt;
&lt;p&gt;--titus&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/IwxX5JfXloE" height="1" width="1"/&gt;</description><feedburner:origLink>http://ivory.idyll.org/blog/feb-09/people-who-dont-use-code-coverage-are-idiots</feedburner:origLink></item>
			<item>
				<title>PyMOTW: tarfile</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/G-kgtjFridk/default</link>
				<pubDate>Sun, 22 Feb 2009 22:44:57 GMT</pubDate>
			<description>&lt;div class="section" id="module-tarfile"&gt;&lt;h1&gt;tarfile &amp;#8211; Tar archive access&lt;/h1&gt;&lt;table class="docutils field-list" frame="void" rules="none"&gt;&lt;col class="field-name" /&gt;&lt;col class="field-body" /&gt;&lt;tbody valign="top"&gt;&lt;tr class="field"&gt;&lt;th class="field-name"&gt;Purpose:&lt;/th&gt;&lt;td class="field-body"&gt;Tar archive access.&lt;/td&gt;&lt;/tr&gt;&lt;tr class="field"&gt;&lt;th class="field-name"&gt;Python Version:&lt;/th&gt;&lt;td class="field-body"&gt;2.3 and later&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The &lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;tarfile&lt;/span&gt;&lt;/tt&gt; module provides read and write access to UNIX tar archives, including compressed files.  In addition to the POSIX standards, several GNU tar extensions are supported.  Various UNIX special file types (hard and soft links, device nodes, etc.) are also handled.&lt;/p&gt;&lt;div class="section" id="testing-tar-files"&gt;&lt;h2&gt;Testing Tar Files&lt;/h2&gt;&lt;p&gt;The is_tarfile() function returns a boolean indicating whether or not the&lt;br /&gt;filename passed as an argument refers to a valid tar file.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;br /&gt;                  &lt;span class="s"&gt;'bad_example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'notthere.tar'&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%20s&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_tarfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;IOError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%20s&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Notice that if the file does not exist, is_tarfile() raises an IOError.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_is_tarfile.py&lt;br /&gt;          README.txt  False&lt;br /&gt;         example.tar  True&lt;br /&gt;     bad_example.tar  False&lt;br /&gt;        notthere.tar  [Errno 2] No such file or directory: 'notthere.tar'&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="reading-meta-data-from-an-archive"&gt;&lt;h2&gt;Reading Meta-data from an Archive&lt;/h2&gt;&lt;p&gt;Use the TarFile class to work directly with a tar archive. It supports methods for reading data about existing archives as well as modifying the archives by adding additional files.&lt;/p&gt;&lt;p&gt;To read the names of the files in an existing archive, use getnames():&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getnames&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The return value is a list of strings with the names of the archive contents:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_getnames.py&lt;br /&gt;['README.txt']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;In addition to names, meta-data about the archive members is available as instances of TarInfo objects.  Load the meta-data via getmembers() and getmember().&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;Modified:&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;Mode    :&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;oct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;Type    :&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;Size    :&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'bytes'&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_getmembers.py&lt;br /&gt;README.txt&lt;br /&gt;        Modified:       Sun Feb 22 11:13:55 2009&lt;br /&gt;        Mode    :       0644&lt;br /&gt;        Type    :       0&lt;br /&gt;        Size    :       75 bytes&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;If you know in advance the name of the archive member, you can retrieve its TarInfo object with getmember().&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'notthere.txt'&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'ERROR: Did not find &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; in tar archive'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; is &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt; bytes'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;If the archive member is not present, getmember() raises a KeyError.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_getmember.py&lt;br /&gt;README.txt is 75 bytes&lt;br /&gt;ERROR: Did not find notthere.txt in tar archive&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="extracting-files-from-an-archive"&gt;&lt;h2&gt;Extracting Files From an Archive&lt;/h2&gt;&lt;p&gt;To access the data from an archive member within your program, use the extractfile() method, passing the member&amp;#8217;s name.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'notthere.txt'&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'ERROR: Did not find &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; in tar archive'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_extractfile.py&lt;br /&gt;README.txt : The examples for the tarfile module use this file and example.tar as data.&lt;br /&gt;&lt;br /&gt;ERROR: Did not find notthere.txt in tar archive&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;If you just want to unpack the archive and write the files to the filesystem, use extract() or extractall() instead.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_extract.py&lt;br /&gt;['README.txt']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="admonition note"&gt;&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;&lt;p class="last"&gt;The standard library documentation includes a note stating that extractall() is safer than extract(), and it should be used in most cases.&lt;/p&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_extractall.py&lt;br /&gt;['README.txt']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;If you only want to extract certain files from the archive, their names can be passed to extractall().&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'example.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'outdir'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_extractall_members.py&lt;br /&gt;['README.txt']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="creating-new-archives"&gt;&lt;h2&gt;Creating New Archives&lt;/h2&gt;&lt;p&gt;To create a new archive, simply open the TarFile with a mode of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;'w'&lt;/span&gt;&lt;/tt&gt;. Any existing file is truncated and a new archive is started. To add files, use the add() method.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'creating archive'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_add.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'adding README.txt'&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'closing'&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Contents:'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_add.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_add.py&lt;br /&gt;creating archive&lt;br /&gt;adding README.txt&lt;br /&gt;closing&lt;br /&gt;&lt;br /&gt;Contents:&lt;br /&gt;README.txt&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="using-alternate-archive-member-names"&gt;&lt;h2&gt;Using Alternate Archive Member Names&lt;/h2&gt;&lt;p&gt;It is possible to add a file to an archive using a name other than the original file name, by constructing a TarInfo object with an alternate &lt;em&gt;arcname&lt;/em&gt; and passing it to addfile().&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'creating archive'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_addfile.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'adding README.txt as RENAMED.txt'&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gettarinfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arcname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'RENAMED.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'closing'&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Contents:'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_addfile.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The archive includes only the changed filename:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_addfile.py&lt;br /&gt;creating archive&lt;br /&gt;adding README.txt as RENAMED.txt&lt;br /&gt;closing&lt;br /&gt;&lt;br /&gt;Contents:&lt;br /&gt;RENAMED.txt&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="writing-data-from-sources-other-than-files"&gt;&lt;h2&gt;Writing Data from Sources Other Than Files&lt;/h2&gt;&lt;p&gt;Sometimes you want to write data to an archive but the data is not in a file on the filesystem. Rather than writing the data to a file, then adding that file to the ZIP archive, you can use addfile() to add data from an open file-like handle.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cStringIO&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'This is the data to write to the archive.'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_addfile_string.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TarInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'made_up_file.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Contents:'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_addfile_string.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;member_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;By first constructing a TarInfo object ourselves, we can give the archive member any name we wish.  After setting the size, we can write the data to the archive using addfile() and passing a &lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;StringIO&lt;/span&gt;&lt;/tt&gt; buffer as a source of the data.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_addfile_string.py&lt;br /&gt;&lt;br /&gt;Contents:&lt;br /&gt;made_up_file.txt&lt;br /&gt;This is the data to write to the archive.&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="appending-to-archives"&gt;&lt;h2&gt;Appending to Archives&lt;/h2&gt;&lt;p&gt;In addition to creating new archives, it is possible to append to an existing file. To open a file to append to it, use mode &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;'a'&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'creating archive'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_append.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'contents:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;br /&gt;                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_append.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'adding index.rst'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_append.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'index.rst'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'contents:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;br /&gt;                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_append.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The resulting archive ends up with 2 members:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_append.py&lt;br /&gt;creating archive&lt;br /&gt;contents: ['README.txt']&lt;br /&gt;adding index.rst&lt;br /&gt;contents: ['README.txt', 'index.rst']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="working-with-compressed-archives"&gt;&lt;h2&gt;Working with Compressed Archives&lt;/h2&gt;&lt;p&gt;Besides regular tar archive files, the tarfile module can work with archives compressed via the gzip or bzip2 protocols.  To open a compressed archive, modify the mode string passed to open() to include &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;quot;:gz&amp;quot;&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;quot;:bz2&amp;quot;&lt;/span&gt;&lt;/tt&gt;, depending on the compression method you want to use.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tarfile&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%-30s&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;%-10s&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'FILENAME'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'SIZE'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_mode&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_compression.tar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_compression.tar.gz'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w:gz'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'tarfile_compression.tar.bz2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w:bz2'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;    &lt;span class="p"&gt;]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;write_mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'README.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_size&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r:*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getmembers&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;When opening an existing archive for reading, you can specify &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;quot;r:*&amp;quot;&lt;/span&gt;&lt;/tt&gt; to have tarfile determine the compression method to use automatically.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tarfile_compression.py&lt;br /&gt;FILENAME                       SIZE&lt;br /&gt;README.txt                     75&lt;br /&gt;tarfile_compression.tar        10240      ['README.txt']&lt;br /&gt;tarfile_compression.tar.gz     213        ['README.txt']&lt;br /&gt;tarfile_compression.tar.bz2    186        ['README.txt']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="admonition-see-also admonition seealso"&gt;&lt;p class="first admonition-title"&gt;See also&lt;/p&gt;&lt;dl class="last docutils"&gt;&lt;dt&gt;&lt;a class="reference external" href="http://docs.python.org/library/tarfile.html"&gt;tarfile&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;The standard library documentation for this module.&lt;/dd&gt;&lt;dt&gt;&lt;a class="reference external" href="http://www.gnu.org/software/tar/manual/html_node/Standard.html"&gt;GNU tar manual&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Documentation of the tar format, including extensions.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;zipfile&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Similar access for ZIP archives.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;gzip&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;GNU zip compression&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;bz2&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;bzip2 compression&lt;/dd&gt;&lt;/dl&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.doughellmann.com/PyMOTW/"&gt;PyMOTW Home&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=WqfZDG04"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?d=41" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=59f3mmc6"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?d=50" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=b2hRCurj"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?i=b2hRCurj" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/doughellmann/python/~4/c-3dz8ClpdM" height="1" width="1" /&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/G-kgtjFridk" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.doughellmann.com/feeds/366843238919048380/comments/default</feedburner:origLink></item>
			<item>
				<title>PyCon 2009: In ur brain, giving you the pythons</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/7pwbxiyzuJI/</link>
				<pubDate>Sun, 22 Feb 2009 04:48:10 GMT</pubDate>
			<description>&lt;p&gt;&lt;a href="http://us.pycon.org/"&gt;&lt;img src="http://us.pycon.org/media/2009/public/pycon2009-horizontal-large-215x135.png" alt="PyCon 2009: Chicago" /&gt;&lt;/a&gt; I, along with a whole heck of a lot of other people will be attending PyCon in march. You should know about this by now, unless you&amp;#8217;re living under a rock, or in a shoebox (I like shoeboxes). &lt;/p&gt;
&lt;p&gt;PyCon 09 is turning out to be one of the ones I am most excited about in some time - barring the fact they let me actually stand up and speak about something, there&amp;#8217;s a ton of other excellent and exciting things going on.&lt;/p&gt;
&lt;p&gt;I will be doing two talks - &amp;#8220;Introduction to Multiprocessing in Python&amp;#8221; on Friday, at 3:20 PM, and &amp;#8220;Concurrency and Distributed Computing with Python Today&amp;#8221; at 3:20 PM Saturday. &lt;/p&gt;
&lt;p&gt;The former talk is easy, given it will be focused on introducing the multiprocessing module to the masses, and taking questions about it (be gentle, I just work here). The latter is a much bigger beast. I&amp;#8217;ve been blogging about my research in my pycon 2009 category, and I still have a pile of things to keep adding to that. The talk will attempt to differentiate concurrency from distributed systems, and show the various toolkits/frameworks/etc in the ecosystem today, to help you build both types of systems.&lt;/p&gt;
&lt;p&gt;Given both talks are 45 minutes in length, I will be publishing my talk notes (my slides are not going to be heavy weight) and other information here.&lt;/p&gt;
&lt;p&gt;In addition to me speaking, which may or may not be exciting, there&amp;#8217;s one helluva ton of other talks which simply look awesome. &lt;/p&gt;
&lt;p&gt;My schedule looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; Thursday: Python Language Summit, where I will endeavor to be smart.
&lt;li&gt; Friday: How to give a python talk
&lt;li&gt; Friday: Using Windmill
&lt;li&gt; Friday: Introduction to Python Profiling or How Python is Developed, to harass Brett.
&lt;li&gt; Friday: Panel - Python VMs
&lt;li&gt; Friday: Building an Automated QA infrastructure using Open Source Tools
&lt;li&gt; Friday: Twisted, AMQP and Thrift: Bridging messaging and RPC for building scalable distributed applications
&lt;li&gt; Friday: My Talk (I figure I should go to it)
&lt;li&gt; Friday: A Whirlwind Excursion through Writing a C Extension or Challenges and Opportunities for Python
&lt;li&gt; Thursday: Plugins and monkeypatching: increasing flexibility, dealing with inflexibility
&lt;li&gt; Thursday: The (lack of) design patterns in Python or the Pinax talk
&lt;li&gt; Thursday: Class Decorators: Radically Simple
&lt;li&gt; Thursday: Panel: Object Relational Mappers: Philosophies and Design Decisions.
&lt;li&gt; Thursday: Drop ACID and think about data (I wonder if we can take this literally, if he has scary slides though, we all might trip balls)
&lt;li&gt; Thursday: My Talk, which is up against Bruce Eckel and Raymond H - I expect no one to show up.
&lt;li&gt; Sunday: Panel: Functional Testing Tools in Python
&lt;li&gt; Sunday: Designing a web framework: Django&amp;#8217;s design decisions
&lt;/ul&gt;
&lt;p&gt;This doesn&amp;#8217;t even cover the open space discussions which I might attend - including the &amp;#8220;&lt;a href="http://us.pycon.org/2009/openspace/WritingAboutPython/" target="_blank"&gt;Writing About Python&lt;/a&gt;&amp;#8221; one Doug Hellmann is putting together as well as the &amp;#8220;&lt;a href="http://us.pycon.org/2009/openspace/teachme-webtesting/" target="_blank"&gt;Teach Me Web Testing&lt;/a&gt;&amp;#8221; one by Steve Holden.&lt;/p&gt;
&lt;p&gt;After the main conference, I&amp;#8217;ll be sticking around until Thursday morning for the sprints, at which point I should be sufficiently burned out on python stuff, I will fully convert over to being a full time burger flipper.&lt;/p&gt;
&lt;p&gt;Right now there are 620 registered people &lt;b&gt;who made their attendance public&lt;/b&gt; I don&amp;#8217;t know how many there are in total.&lt;/p&gt;
&lt;p&gt;Hope to see you there!&lt;/p&gt;
&lt;div&gt;&lt;img src="http://jessenoller.com/wp-content/uploads/2009/02/funny-pictures-cat-dog-paper-bag-shrubbery-holy-grail.jpg" alt="funny-pictures-cat-dog-paper-bag-shrubbery-holy-grail.jpg" border="0" width="500" height="329" /&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://feedads.googleadservices.com/~a/U7rzzJ21MX27vXUVjDzNoDd6_po/a"&gt;&lt;img src="http://feedads.googleadservices.com/~a/U7rzzJ21MX27vXUVjDzNoDd6_po/i" border="0" ismap="true" /&gt;&lt;/a&gt;&lt;/p&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/7pwbxiyzuJI" height="1" width="1"/&gt;</description><feedburner:origLink>http://feedproxy.google.com/~r/Jessenollercom/~3/8YrHVxBmfK8/</feedburner:origLink></item>
			<item>
				<title>"Writing About Python" at PyCon</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/2xvu8828ido/default</link>
				<pubDate>Fri, 20 Feb 2009 20:49:48 GMT</pubDate>
			<description>The Python writing community has never been stronger.  From &lt;a href="http://planet.python.org/"&gt;blogs&lt;/a&gt; to &lt;a href="http://www.pythonmagazine.com/"&gt;magazines&lt;/a&gt; to a slew of recent releases from &lt;a href="http://www.oreilly.com/"&gt;O'Reilly&lt;/a&gt;, &lt;a href="http://www.packtpub.com/"&gt;Packt&lt;/a&gt;, &lt;a href="http://www.manning.com/"&gt;Manning&lt;/a&gt;, &lt;a href="http://apress.com/"&gt;Apress&lt;/a&gt;, and other publishers there a more opportunities than ever before for anyone wanting to write &lt;em&gt;about&lt;/em&gt; Python in some form.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://us.pycon.org/"&gt;&lt;img src="http://us.pycon.org/media/2009/public/pycon2009-vertical-small-100x225.png" alt="PyCon 2009: Chicago" align="left" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Of course, authoring is only one aspect of producing high quality professional writing.  As an editor, it's no surprise that I think all authors can benefit from having someone else read their work.  Even an informal review can help identify gaps in an explanation or problems with flow, not to mention typos.&lt;br /&gt;&lt;br /&gt;Writers, reviewers, and editors can all benefit from sharing tips, offering advice on tricky problem passages, or just chatting about ongoing projects.  That list sounds just like the sorts of things we talk about when discussing programming, doesn't it?&lt;br /&gt;&lt;br /&gt;I'd like to bring people together in person for a group discussion and a chance to network.  To kick things off, I'm working on organizing a "meetup" as an open space session at PyCon in March.  If you are a blogger, published writer, reviewer, or editor -- or &lt;em&gt;aspire&lt;/em&gt; to be -- I want you to come and participate.  No prior experience is necessary, everyone is welcome.&lt;br /&gt;&lt;br /&gt;Let's connect people interested in doing technical reviews with authors and editors.  Let's introduce potential writers to the editors and publishers.  Let's learn from one another and improve our prose, the same way we improve our code.&lt;br /&gt;&lt;br /&gt;We'll have to wait to schedule a precise time until the conference, but right now I'm thinking about late Saturday morning or early afternoon.  If you are interested in attending, please post a comment so I can gauge the size of the room we'll need.  If you have a preference for the time, make sure to include that information.  And if you have ideas for things we should talk about, let's hear them.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; Although I was thinking of "print" writing, other forms of publishing like podcasting are welcome, too.  We need more good Python podcasts!&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=ubmn19YB"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?d=41" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=Q6N6N0M3"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?d=50" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=GsUFTqAY"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?i=GsUFTqAY" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/doughellmann/python/~4/5zOOCStxAko" height="1" width="1" /&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/2xvu8828ido" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.doughellmann.com/feeds/8965201997211048830/comments/default</feedburner:origLink></item>
			<item>
				<title>Good code coverage: Necessity vs Sufficiency</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/NB1Zp48gUH4/necessity-vs-sufficiency</link>
				<pubDate>Thu, 19 Feb 2009 14:56:02 GMT</pubDate>
			<description>&lt;div class="document"&gt;
&lt;p&gt;I get really frustrated with posts that claim &lt;a class="reference" href="http://agilesoftwaredevelopment.com/blog/janusz-gorycki/your-unit-tests-are-useless"&gt;your unit tests lie to
you&lt;/a&gt;
or &lt;a class="reference" href="http://binstock.blogspot.com/2007/11/fallacy-of-100-code-coverage.html"&gt;100% code coverage is fallacious&lt;/a&gt;
or &lt;a class="reference" href="http://nedbatchelder.com/blog/200710/flaws_in_coverage_measurement.html"&gt;there are flaws in coverage measurement&lt;/a&gt;.
These are sensationalist headlines that encourage bad behavior, by
confusing new or inexperienced or argumentative or lazy developers:
&amp;quot;well, we all know test coverage isn't that important...&amp;quot;&lt;/p&gt;
&lt;p&gt;There is a fundamental confusion here between &lt;em&gt;necessary&lt;/em&gt; and
&lt;em&gt;sufficient&lt;/em&gt;.  In plain English, things that are &lt;em&gt;necessary&lt;/em&gt; are,
well, necessary for a process; things that are &lt;em&gt;sufficient&lt;/em&gt; are,
collectively, sufficient.&lt;/p&gt;
&lt;p&gt;One does not imply the other.  Tires are &lt;em&gt;necessary&lt;/em&gt; but not
&lt;em&gt;sufficient&lt;/em&gt; for a car.&lt;/p&gt;
&lt;p&gt;Why do I bring this up?  Because near-100% code coverage is basically
&lt;em&gt;necessary&lt;/em&gt; for a complete automated test suite, but not sufficient.&lt;/p&gt;
&lt;p&gt;If you do not have near-100% code coverage, then some portion of your
code is not being executed by your tests.  That means that code is
untested.  It can't possibly be tested if you aren't executing it!&lt;/p&gt;
&lt;p&gt;(As a corollary, &lt;a class="reference" href="http://binstock.blogspot.com/2007/11/fallacy-of-100-code-coverage.html"&gt;no test that adds to code coverage is useless&lt;/a&gt;.  It may not be
as useful as it could be, but it is still running code that is otherwise
untested.  Room for improvement does not equal uselessness!)&lt;/p&gt;
&lt;p&gt;OTOH, there are many reasons that 100% code coverage isn't sufficient to
make your test suite good.  For one, code coverage isn't branch coverage.
For another, code coverage can't tell you if your feature set meets your
client's needs or is in fact functional -- all it can do is tell you that
your feature set meets your expectations at the moment.&lt;/p&gt;
&lt;p&gt;So, let me suggest this simple pair of statements:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;High (statement) code coverage in your tests is &lt;em&gt;important&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;High code coverage doesn't guarantee that your tests are complete.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I feel like high code coverage is actually a pretty low bar for a
project.  Whether or not you're using TDD, if you don't have high code
coverage numbers, you're not really testing very thoroughly; it's
generally pretty easy to amp up your code coverage numbers quickly,
although writing the test fixtures can be a problem.  I'll talk a bit
about this in my PyCon talk.&lt;/p&gt;
&lt;p&gt;Regardless of your tests suite, &lt;a class="reference" href="http://geeksinboston.com/2009/01/07/you-will-probably-fail-in-a-boring-and-project-specific-way/"&gt;your project will probably fail in a boring and project-specific
way&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;--titus&lt;/p&gt;
&lt;p&gt;P.S. &lt;a class="reference" href="http://coverclock.blogspot.com/2008/10/while-code-coverage-is-necessary-but.html"&gt;Many people do get it, which is nice.&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/NB1Zp48gUH4" height="1" width="1"/&gt;</description><feedburner:origLink>http://ivory.idyll.org/blog/feb-09/necessity-vs-sufficiency</feedburner:origLink></item>
			<item>
				<title>simplejson 2.0.9</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/B-NgWQatWvM/</link>
				<pubDate>Thu, 19 Feb 2009 09:00:57 GMT</pubDate>
			<description>&lt;div class="document"&gt;
&lt;!-- -*- mode: rst -*- --&gt;
&lt;p&gt;&lt;a class="reference" href="http://undefined.org/python/#simplejson"&gt;simplejson&lt;/a&gt; (&lt;a class="reference" href="http://simplejson.googlecode.com/svn/tags/simplejson-2.0.9/docs/index.html"&gt;documentation&lt;/a&gt;) is a simple, fast, complete, correct and extensible &lt;a class="reference" href="http://json.org/"&gt;JSON&lt;/a&gt; (&lt;a class="reference" href="http://www.ietf.org/rfc/rfc4627.txt"&gt;RFC 4627&lt;/a&gt;) encoder/decoder for Python 2.4+.  It is pure Python code with no dependencies, but features an optional C extension for speed-ups.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference" href="http://undefined.org/python/#simplejson"&gt;simplejson&lt;/a&gt; 2.0.9 is a major bug-fix update:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Adds cyclic GC to the Encoder and Scanner speedups, which could've caused uncollectible cycles in some cases when using custom parser or encoder functions&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/B-NgWQatWvM" height="1" width="1"/&gt;</description><feedburner:origLink>http://bob.pythonmac.org/archives/2009/02/18/simplejson-209/</feedburner:origLink></item>
			<item>
				<title>The History of Python: Adding Support for User-defined Classes</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/tYQLgFl8-gw/</link>
				<pubDate>Thu, 19 Feb 2009 08:00:16 GMT</pubDate>
			<description>&lt;div class="blogmark segment"&gt;&lt;p&gt;&lt;a href="http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html"&gt;The History of Python: Adding Support for User-defined Classes&lt;/a&gt;. Guido designed the run-time representation first, and tried to design the syntax to include as few new parsing concepts as possible. The origins of explicit self are also explained.&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/tYQLgFl8-gw" height="1" width="1"/&gt;</description><feedburner:origLink>http://simonwillison.net/2009/Feb/18/history/</feedburner:origLink></item>
			<item>
				<title>DB2 support for Django is coming</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/VG1wVy6A5GM/</link>
				<pubDate>Thu, 19 Feb 2009 07:58:50 GMT</pubDate>
			<description>&lt;div class="blogmark segment"&gt;&lt;p&gt;&lt;a href="http://antoniocangiano.com/2009/02/18/db2-support-for-django-is-coming/"&gt;DB2 support for Django is coming&lt;/a&gt;. From IBM, under the Apache 2.0 License. I&amp;#8217;m not sure if this makes it hard to bundle it with the rest of Django, which uses the BSD license.&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/VG1wVy6A5GM" height="1" width="1"/&gt;</description><feedburner:origLink>http://simonwillison.net/2009/Feb/18/db2/</feedburner:origLink></item>
			<item>
				<title>Creating a web framework with WSGI video</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/ySi0CYa2H_s/</link>
				<pubDate>Wed, 18 Feb 2009 11:54:14 GMT</pubDate>
			<description>&lt;p&gt;&lt;a href="http://www.vimeo.com/3258566"&gt;Creating a web framework with WSGI on Vimeo&lt;/a&gt;&lt;br /&gt;
&lt;blockquote&gt;The Michigan Python Users Group (MichiPUG) meeting topic from February 2009, presented by Kevin Dangoor. This screencast video shows us using WSGI components to build up a web framework piece-by-piece.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;By the way, for people who are interested in working on the &lt;a href="http://labs.mozilla.com/projects/bespin/"&gt;Bespin&lt;/a&gt; server, this is the kind of &amp;#8220;web framework&amp;#8221; that the server is built upon.&lt;/p&gt;
&lt;div class="zemanta-pixie"&gt;&lt;img class="zemanta-pixie-img" src="http://img.zemanta.com/pixy.gif?x-id=986f85a9-2510-4149-aade-ce9a5598de27" /&gt;&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/ySi0CYa2H_s" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.blueskyonmars.com/2009/02/17/creating-a-web-framework-with-wsgi-video/</feedburner:origLink></item>
			<item>
				<title>Announcing django-viewtools</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/Txs6FUubzjM/</link>
				<pubDate>Wed, 18 Feb 2009 06:35:31 GMT</pubDate>
			<description>&lt;div class="blogmark segment"&gt;&lt;p&gt;&lt;a href="http://eric.themoritzfamily.com/2009/02/17/announcing-django-viewtools/"&gt;Announcing django-viewtools&lt;/a&gt;. A really excellent idea&amp;#8212;run ./manage.py viewtools --pdb /path/on/site/ to debug a view in your Django project that is raising an error using the Python debugger, or use --profile to run the full request cycle for that URL through the profiler.&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/Txs6FUubzjM" height="1" width="1"/&gt;</description><feedburner:origLink>http://simonwillison.net/2009/Feb/17/announcing/</feedburner:origLink></item>
			<item>
				<title>CloudMade: A Summary of the Future of Mapping</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/cTmg1xoHkPM/</link>
				<pubDate>Tue, 17 Feb 2009 20:25:53 GMT</pubDate>
			<description>&lt;div class="blogmark segment"&gt;&lt;p&gt;&lt;a href="http://blog.cloudmade.com/2009/02/16/a-summary-of-the-future-of-mapping/#more-126"&gt;CloudMade: A Summary of the Future of Mapping&lt;/a&gt;. CloudMade are now offering commercially supported APIs on top of OpenStreetMap, including geocoding, routing and tile access libraries in Python/Ruby/Java and a very neat theming tool that lets you design your own map styles. This is really going to kick innovation around OpenStreetMap up a notch.&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/cTmg1xoHkPM" height="1" width="1"/&gt;</description><feedburner:origLink>http://simonwillison.net/2009/Feb/17/cloudmade/</feedburner:origLink></item>
			<item>
				<title>Dulwich</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/71DNiyGViWI/</link>
				<pubDate>Tue, 17 Feb 2009 07:27:56 GMT</pubDate>
			<description>&lt;div class="blogmark segment"&gt;&lt;p&gt;&lt;a href="http://samba.org/~jelmer/dulwich/"&gt;Dulwich&lt;/a&gt;. A pure Python implementation of the Git file format and protocols. Reinforces my impression that a key to Git&amp;#8217;s success is stable, well designed and documented on-disk formats.&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/71DNiyGViWI" height="1" width="1"/&gt;</description><feedburner:origLink>http://simonwillison.net/2009/Feb/16/dulwich/</feedburner:origLink></item>
			<item>
				<title>Write to a Google Spreadsheet from a Python script</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/udOKTxNGpJk/</link>
				<pubDate>Tue, 17 Feb 2009 06:02:06 GMT</pubDate>
			<description>&lt;div class="blogmark segment"&gt;&lt;p&gt;&lt;a href="http://www.mattcutts.com/blog/write-google-spreadsheet-from-python/"&gt;Write to a Google Spreadsheet from a Python script&lt;/a&gt;. I didn&amp;#8217;t know Google Spreadsheets could directly serve dynamic images that automatically update when the underlying data changes.&lt;/p&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/udOKTxNGpJk" height="1" width="1"/&gt;</description><feedburner:origLink>http://simonwillison.net/2009/Feb/16/write/</feedburner:origLink></item>
			<item>
				<title>Django Tech Blog</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/018wUupHtPA/</link>
				<pubDate>Tue, 17 Feb 2009 05:32:37 GMT</pubDate>
			<description>&lt;p&gt;The new Django blog system I have been working on is virtually finished, I&amp;#8217;m just testing it at the moment. Now I know that by writing my own blog system I will miss out on all the capabilities of a full featured and mature system, such as Wordpress; but my new system &amp;#8212; which I call Django Techblog &amp;#8212; has a few features that Wordpress doesn&amp;#8217;t, but more importantly, it works just the way I want it to.&lt;/p&gt;
&lt;p&gt;One of those new features is the ability to insert syntax highlighted code in to comments, which is very useful for a techy blog! I&amp;#8217;ve created a post on the beta site, and I&amp;#8217;d like to invite you to pop over and test the commenting system. I&amp;#8217;ll delete the comments when I&amp;#8217;m satisfied it is working nicely and I can replace www.willmcgugan.com. So feel free to play about with it&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://beta.willmcgugan.com/2009/2/16/django-techblog-comment-test/"&gt;http://beta.willmcgugan.com/2009/2/16/django-techblog-comment-test/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Any comments about the design or general functionality of the blog would also be welcome!&lt;/p&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/018wUupHtPA" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.willmcgugan.com/2009/02/16/django-tech-blog/</feedburner:origLink></item>
			<item>
				<title>Explaining Why Interfaces Are Great</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/2_pD3eIIA78/default</link>
				<pubDate>Mon, 16 Feb 2009 22:40:20 GMT</pubDate>
			<description>&lt;div&gt;&lt;h2&gt;Why?&lt;/h2&gt;Why use &lt;a href="http://wiki.zope.org/zope3/WhatAreInterfaces"&gt;interfaces&lt;/a&gt;? Especially with Python's new &lt;a href="http://www.python.org/dev/peps/pep-3119/"&gt;ABCs&lt;/a&gt;, is there really a use for them?&lt;br /&gt;&lt;br /&gt;Some of us Zope Interface fans &amp;#8212; names withheld to protect the guilty, although you may feel free to unmask yourselves in the comments if you like &amp;#8212; have expressed frustration that ABCs beat out interfaces for inclusion of the standard library.&amp;#160; However, I recently explored various mailing lists, Interfaces literature, and blogs, and haven't found a coherent description of &lt;i&gt;why&lt;/i&gt; one would prefer interfaces over ABCs.&amp;#160; It's no surprise that Zope's interface package is poorly understood, given that nobody has even explained it!&amp;#160; In fact, &lt;a href="http://www.python.org/dev/peps/pep-3119/#abcs-vs-interfaces"&gt;PEP 3119 specifically says&lt;/a&gt;:&lt;blockquote&gt;For now, I'll leave it to proponents of Interfaces &lt;strong&gt;to explain why Interfaces are better&lt;/strong&gt;.&lt;/blockquote&gt;It seems that nobody has taken up the challenge.&lt;br /&gt;&lt;br /&gt;I remember Jim Fulton trying to explain this to me many years ago, at a PyCon in Washington DC. &amp;#160;I definitely didn't understand it then. &amp;#160;I was reluctant to replace the crappy little interfaces system in Twisted at the time with something big and complicated-looking. &amp;#160; Luckily the other Twisted committers prevailed upon me, and Zope Interface has saved us from maintaining that misdesigned and semi-functional mess.&lt;br /&gt;&lt;br /&gt;During that explanation, I remember that Jim kept saying that interfaces provided a model to&amp;#160;"reason about intent". &amp;#160;At the time I didn't understand why you'd want to reason about intent in code. &amp;#160;Wouldn't the docstrings and the implementation specify the intent clearly enough? &amp;#160;Now, I can see exactly what he's talking about and I use the features he was referring to all the time. &amp;#160;I don't know how I'd write large Python programs without them.&lt;br /&gt;&lt;h2&gt;Caveat&lt;/h2&gt;This isn't a rant against ABCs.&amp;#160; I think ABCs are mostly pretty good, certainly an improvement over what was (or rather, wasn't) there before.&amp;#160; ABCs provide things that Interfaces don't, like the new @abstractmethod and @abstractproperty decorators. Plus, one of the irritating things about using zope.interface is that the metadata about standard objects in zope.interface.common is not hooked up to anything: &lt;code&gt;IMapping.providedBy({})&lt;/code&gt; returns &lt;code&gt;False&lt;/code&gt;. &amp;#160;ABCs will provide that metadata in the standard library, making zope.interface that much more useful once it has been upgraded to understand the declarations that the &lt;code&gt;collections&lt;/code&gt; and &lt;code&gt;numbers&lt;/code&gt; modules provide.&lt;br /&gt;&lt;br /&gt;So, on to the main event: what do Zope Interfaces provide which makes them so great?&lt;br /&gt;&lt;h2&gt;Clarity&lt;/h2&gt;Let's say we have an idea of something called a "vehicle".&amp;#160; We can represent it as one of two things: a real base class (Vehicle), an ABC (AVehicle) or an Interface (IVehicle).&lt;br /&gt;&lt;br /&gt;There are a set of operations that interfaces and base-classes share.&amp;#160; We can ask, "is this thing I have a vehicle"?&amp;#160; In the base-class case we spell that 'if isinstance(something, Vehicle)'.&amp;#160; In the interfaces case, we say 'if IVehicle.providedBy(something)'.&amp;#160; We can ask, "will instances of this type be a vehicle?".&amp;#160; For an interface, we say 'if IVehicle.implementedBy(Something)', and for a base class we say 'issubclass(Something, Vehicle)'.&amp;#160; With the new hooks provided by the ABCs in 2.6 and 3.0, these are almost equivalent.&amp;#160; With zope.interface, you can subclass &lt;code&gt;InterfaceClass&lt;/code&gt; and write your own &lt;code&gt;providedBy&lt;/code&gt; method.&amp;#160; With the ABC system, you subclass &lt;code&gt;type&lt;/code&gt; and implement &lt;code&gt;__instancecheck__&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;However, there are some questions you can't quite cleanly ask of the ABC system.&amp;#160; For one thing, what does it really &lt;i&gt;mean&lt;/i&gt; to be a Vehicle?&amp;#160; If you are looking at AVehicle, you can't tell the difference between implementation details and the specification of the interface.&amp;#160; You can use dir() and ignore a few of the usual suspects &amp;#8212; &lt;code&gt;__doc__&lt;/code&gt;, &lt;code&gt;__module__&lt;/code&gt;, &lt;code&gt;__name__&lt;/code&gt;, &lt;code&gt;_abc_negative_cache_version&lt;/code&gt; &amp;#8212; but what about the quirkier bits?&amp;#160; Metaclasses, inherited attributes, and so on?&amp;#160; There's probably some way to do it, but I certainly can't figure it out quickly enough to include in this article.&amp;#160; In other words, types have two jobs: they might be ABCs, or they might be types, or they might be both, and it's impossible to separate those responsibilities.&lt;br /&gt;&lt;br /&gt;With an Interface, this question is a lot easier to ask.&amp;#160; For a quick look, list(IVehicle) will give a complete list of all the attributes expected of a vehicle, as strings.&amp;#160; If you want more detail, IVehicle.namesAndDescriptions() and Method.getSignatureInfo() will oblige.&lt;br /&gt;&lt;br /&gt;Since the interface encapsulates only what an object is &lt;i&gt;supposed&lt;/i&gt; to be, and no functionality of its own, it's possible for frameworks to inspect them and provide much nicer error messages when objects don't match their expectations.&amp;#160; &lt;code&gt;zope.interface.verifyClass&lt;/code&gt; and &lt;code&gt;zope.interface.verifyObject&lt;/code&gt; can tell you, both for error-reporting and unit-testing purposes, whether an object &lt;i&gt;looks&lt;/i&gt; like a proper vehicle or not, without actually trying to drive it around.&lt;br /&gt;&lt;h2&gt;Flexibility&lt;/h2&gt;At the most basic level, interfaces are more flexible because they are objects.&amp;#160; ABCs aren't objects, at least in the message-passing smalltalk sense; they are a collection of top-level functions and some rules about how those functions apply to types.&amp;#160; If you want to change the answer to &lt;code&gt;isinstance()&lt;/code&gt;, you need to register a type by using &lt;code&gt;ABCMeta.register&lt;/code&gt; or overriding &lt;code&gt;__instancecheck__&lt;/code&gt; on a real subclass of &lt;code&gt;type&lt;/code&gt;.&amp;#160; If you want to change the answer to &lt;code&gt;providedBy&lt;/code&gt;, for example for a unit test, all you need is an object with a providedBy method.&lt;br /&gt;&lt;br /&gt;Of course, you can do it "for real" with an &lt;code&gt;InterfaceClass&lt;/code&gt;, but you don't &lt;i&gt;need&lt;/i&gt; to.&amp;#160; In other words, its semantics are those of a normal method call.&lt;br /&gt;&lt;br /&gt;Interfaces aren't completely self-contained, of course: there are top-level functions that operate on interfaces, like verifyObject.&amp;#160; However, there's an interface to describe what is expected:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from zope.interface.interfaces import Interface, IInterface&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; IInterface.providedBy(Interface)&lt;br /&gt;True&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;There's also the issue of who implements what.&amp;#160; For example, you might have a plug-in system which requires modules to implement some functionality.&amp;#160; Generally speaking, modules are instances of ModuleType, so specifying that all modules implement some type with an ABC is somewhat awkward.&amp;#160; With an interface, however, there is a specific facility for this: you put a &lt;code&gt;moduleProvides(IVehicle)&lt;/code&gt; declaration at the top of your module.&lt;br /&gt;&lt;br /&gt;In zope.interface, there is a very clear conceptual break between &lt;i&gt;implements&lt;/i&gt; and &lt;i&gt;provides&lt;/i&gt;.&amp;#160; A module may &lt;i&gt;provide&lt;/i&gt; an interface &amp;#8212; i.e. be an object which satisfies that interface at runtime &amp;#8212; without there being any object that &lt;i&gt;implements&lt;/i&gt; that interface &amp;#8212; i.e. is a type whose instances automatically provide it.&amp;#160; This distinction comes in handy when avoiding certain things.&amp;#160; This distinction exists with ABCs; either you "are a subclass of" a type or you "are an instance of" a type, but the language around it is more awkward and vague, especially since you can be a "virtual instance" or "virtual subclass" now as well.&lt;br /&gt;&lt;br /&gt;There's also the issue of dynamic proxies.&amp;#160; If you have a wrapper which provides security around another object, or transparent remote access to another object, or records method calls (and so on) the wrapper really wants to say that it &lt;i&gt;provides&lt;/i&gt; the interfaces provided by the object it is wrapping, but the wrapper type does not &lt;i&gt;implement&lt;/i&gt; those interfaces.&amp;#160; In other words, different instances of your wrapper class will actually provide different interfaces.&amp;#160; With zope.interface you can declare this via the &lt;code&gt;directlyProvides&lt;/code&gt; declaration.&amp;#160; With ABCs, this is not generally possible because &lt;code&gt;ABCMeta.register&lt;/code&gt; will only work on a type.&lt;br /&gt;&lt;h2&gt;Adaptation&lt;/h2&gt;Let's say I have an object that provides IVehicle.&amp;#160; I want to display it somehow &amp;#8212; and in today's web-centric world, that probably means "I want to generate some HTML".&amp;#160; How do I get from here to there?&amp;#160; ABCs don't provide an answer to that question.&amp;#160; Interfaces don't do that &lt;i&gt;directly&lt;/i&gt; either, but they do provide a mechanism which allows you to provide an answer: you can &lt;i&gt;adapt&lt;/i&gt; from one interface to another.&lt;br /&gt;&lt;br /&gt;I'm not going to get into the intricacies of exactly how adaptation works in zope.interface, since it isn't important to understand most of the time.&amp;#160; Suffice it to say you can adapt based on specific hooks that are registered, based on the type an object is, or based on what interfaces it provides.&lt;br /&gt;&lt;br /&gt;The gist of it is that you have some thing that you don't know what it is, and you want an object that provides IHTMLRenderer.&amp;#160; The way you express that intent is:&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; renderer = IHTMLRenderer(someObject)&lt;br /&gt;&lt;br /&gt;If there are no rules for adapting an object like the one you have passed to an IHTMLRenderer, then you will get an exception - which is all that will happen, normally.&amp;#160; However, this point of separation between the contract that your code expects and the concrete type that your code ends up actually talking to can be very useful.&lt;br /&gt;&lt;br /&gt;The larger Zope application server has a rich and complex set of tools for defining which adapter is appropriate in which context, but Twisted has a very simple interface to adaptation.&amp;#160; You simply register an adapter, which is a 1-argument callable that takes an object that conforms to some interface or is an instance of some class, and returns an object that provides another interface. &amp;#160;Here's how you do it:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;#160;&amp;#160;&amp;#160; from twisted.python.components import registerAdapter&lt;br /&gt;&amp;#160; &amp;#160; class VehicleRenderer(object):&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; "Render a vehicle as HTML"&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; implements(IHTMLRenderer)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; def __init__(self, vehicle):&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; self.vehicle = vehicle&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; def renderHTML(self):&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return "&amp;lt;h1&amp;gt;A Great Vehicle %s (%s)&amp;lt;/h1&amp;gt;" % (&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; self.vehicle.make.name,&lt;br /&gt;&amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;&amp;#160; self.vehicle.model.name)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; registerAdapter(VehicleRenderer, IVehicle, IHTMLRenderer)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now, whenever you do IHTMLRenderer(someVehicle), you'll get a VehicleRenderer(someVehicle).&lt;br /&gt;&lt;br /&gt;Your code for rendering now doesn't need any special-case knowledge about particular types. &amp;#160;It is written to an interface, and it's very easy to figure out which one; it says "IHTMLRenderer" right there. &amp;#160;It's also easy to find implementors of that interface; just grep for "implements.*IHTMLRenderer" or similar. &amp;#160;Or, use pydoctor and &lt;a href="http://twistedmatrix.com/documents/current/api/twisted.internet.interfaces.IProtocol.html"&gt;look at the "known implementations" section&lt;/a&gt; for the interface in question.&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;In a super-dynamic language like Python, you don't &lt;i&gt;need&lt;/i&gt; a system for explicit abstract interfaces.&amp;#160; No compiler is going to shoot you for calling a 'foo' method.&amp;#160; But, formal interface definitions serve many purposes.&amp;#160; They can function as documentation, as a touchstone for code which wants to clearly report programming errors ("warning:&amp;#160; MyWidget claims to implement IWidget, but doesn't implement a 'doWidgetStuff' method"), and a mechanism for indirection when you know what contract your code wants but you don't know what implementation will necessarily satisfy it (adaptation).&lt;br /&gt;&lt;br /&gt;Even with a standard library mechanism for doing some of these things, Zope Interface remains a highly useful library, and if you are working on a large Python system you should consider augmenting its organization and documentation with this excellent tool.&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/glyph/~4/uxc5Yio6kyA" height="1" width="1" /&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/2_pD3eIIA78" height="1" width="1"/&gt;</description><feedburner:origLink>http://glyph.twistedmatrix.com/feeds/762780728735916695/comments/default</feedburner:origLink></item>
			<item>
				<title>simplejson 2.0.8</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/dTk40PTncF4/</link>
				<pubDate>Mon, 16 Feb 2009 09:56:05 GMT</pubDate>
			<description>&lt;div class="document"&gt;
&lt;!-- -*- mode: rst -*- --&gt;
&lt;p&gt;&lt;a class="reference" href="http://undefined.org/python/#simplejson"&gt;simplejson&lt;/a&gt; (&lt;a class="reference" href="http://simplejson.googlecode.com/svn/tags/simplejson-2.0.8/docs/index.html"&gt;documentation&lt;/a&gt;) is a simple, fast, complete, correct and extensible &lt;a class="reference" href="http://json.org/"&gt;JSON&lt;/a&gt; (&lt;a class="reference" href="http://www.ietf.org/rfc/rfc4627.txt"&gt;RFC 4627&lt;/a&gt;) encoder/decoder for Python 2.4+.  It is pure Python code with no dependencies, but features an optional C extension for speed-ups.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference" href="http://undefined.org/python/#simplejson"&gt;simplejson&lt;/a&gt; 2.0.8 is a minor bug-fix update:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Documentation fixes&lt;/li&gt;
&lt;li&gt;Fixes encoding True and False as keys&lt;/li&gt;
&lt;li&gt;Fixes checking for True and False by identity for several parameters&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/dTk40PTncF4" height="1" width="1"/&gt;</description><feedburner:origLink>http://bob.pythonmac.org/archives/2009/02/15/simplejson-208/</feedburner:origLink></item>
			<item>
				<title>PyMOTW: grp</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/JtFMeZOk0-E/default</link>
				<pubDate>Mon, 16 Feb 2009 00:19:24 GMT</pubDate>
			<description>&lt;div class="section" id="module-grp"&gt;&lt;h1&gt;grp &amp;#8211; Unix Group Database&lt;/h1&gt;&lt;table class="docutils field-list" frame="void" rules="none"&gt;&lt;col class="field-name" /&gt;&lt;col class="field-body" /&gt;&lt;tbody valign="top"&gt;&lt;tr class="field"&gt;&lt;th class="field-name"&gt;Purpose:&lt;/th&gt;&lt;td class="field-body"&gt;Read group data from Unix group database.&lt;/td&gt;&lt;/tr&gt;&lt;tr class="field"&gt;&lt;th class="field-name"&gt;Python Version:&lt;/th&gt;&lt;td class="field-body"&gt;1.4 and later&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The grp module can be used to read information about Unix groups from the group database (usually &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/group&lt;/span&gt;&lt;/tt&gt;).  The read-only interface returns tuple-like objects with named attributes for the standard fields of a group record.&lt;/p&gt;&lt;table border="1" class="docutils"&gt;&lt;colgroup&gt;&lt;col width="12%" /&gt;&lt;col width="21%" /&gt;&lt;col width="67%" /&gt;&lt;/colgroup&gt;&lt;thead valign="bottom"&gt;&lt;tr&gt;&lt;th class="head"&gt;Index&lt;/th&gt;&lt;th class="head"&gt;Attribute&lt;/th&gt;&lt;th class="head"&gt;Meaning&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;br /&gt;&lt;tbody valign="top"&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;gr_name&lt;/td&gt;&lt;td&gt;Name&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;gr_passwd&lt;/td&gt;&lt;td&gt;Password, if any (encrypted)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;gr_gid&lt;/td&gt;&lt;td&gt;Numerical id (integer)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;gr_mem&lt;/td&gt;&lt;td&gt;Names of group members&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The name and password values are both strings, the GID is an integer, and the members are reported as a list of strings.&lt;/p&gt;&lt;div class="section" id="querying-all-groups"&gt;&lt;br /&gt;&lt;h2&gt;Querying All Groups&lt;/h2&gt;&lt;p&gt;Suppose you need to print a report of all of the &amp;#8220;real&amp;#8221; groups on a system, including their members  (for our purposes, &amp;#8220;real&amp;#8221; is defined as having a name not starting with &amp;#8220;_&amp;#8221;).  To load the entire password database, you would use getgrall().  The return value is a list with an undefined order, so you probably want to sort it before printing the report.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;grp&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;operator&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# Load all of the user data, sorted by username&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;all_groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getgrall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;interesting_groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;br /&gt;                            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_groups&lt;/span&gt; &lt;br /&gt;                            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'_'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;br /&gt;                            &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrgetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'gr_name'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# Find the longest length for the name&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;name_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;interesting_groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# Print report headers&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%-*s&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;%4s&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;%10s&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;br /&gt;             &lt;span class="s"&gt;'GID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;br /&gt;             &lt;span class="s"&gt;'Password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;             &lt;span class="s"&gt;'Members'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;name_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'----'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;30&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# Print the data&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;interesting_groups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;br /&gt;                 &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_gid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;br /&gt;                 &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_passwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                 &lt;span class="s"&gt;', '&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_mem&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python grp_getgrall.py&lt;br /&gt;Name                                      GID   Password Members&lt;br /&gt;---------------------------------------- ---- ---------- ------------------------------&lt;br /&gt;accessibility                              90          *&lt;br /&gt;admin                                      80          * root, dhellmann&lt;br /&gt;authedusers                                50&lt;br /&gt;bin                                         7          *&lt;br /&gt;certusers                                  29          * root, _jabber, _postfix, _cyrus, _calendar&lt;br /&gt;com.apple.access_screensharing-disabled   101            dhellmann&lt;br /&gt;consoleusers                               53&lt;br /&gt;daemon                                      1          * root&lt;br /&gt;dhellmann                                 501&lt;br /&gt;dialer                                     68          *&lt;br /&gt;everyone                                   12&lt;br /&gt;group                                      16&lt;br /&gt;interactusers                              51&lt;br /&gt;kmem                                        2          * root&lt;br /&gt;localaccounts                              61&lt;br /&gt;mail                                        6          *&lt;br /&gt;netaccounts                                62&lt;br /&gt;netusers                                   52&lt;br /&gt;network                                    69          *&lt;br /&gt;nobody                                     -2          *&lt;br /&gt;nogroup                                    -1          *&lt;br /&gt;operator                                    5          * root&lt;br /&gt;owner                                      10&lt;br /&gt;postgres                                  401&lt;br /&gt;procmod                                     9          * root&lt;br /&gt;procview                                    8          * root&lt;br /&gt;racemi                                    500            dhellmann&lt;br /&gt;smmsp                                      25&lt;br /&gt;staff                                      20          * root, test&lt;br /&gt;sys                                         3          * root&lt;br /&gt;tty                                         4          * root&lt;br /&gt;utmp                                       45          *&lt;br /&gt;wheel                                       0          * root&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="group-memberships-for-a-user"&gt;&lt;br /&gt;&lt;h2&gt;Group Memberships for a User&lt;/h2&gt;&lt;p&gt;Another common task might be to print a list of all the groups for a given user:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;grp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'dhellmann'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;grp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getgrall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_mem&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'belongs to:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;', '&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python grp_groups_for_user.py&lt;br /&gt;dhellmann belongs to: _lpadmin, admin, com.apple.access_screensharing-disabled, racemi&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="finding-a-group-by-name"&gt;&lt;h2&gt;Finding a Group By Name&lt;/h2&gt;&lt;p&gt;As with &lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;pwd&lt;/span&gt;&lt;/tt&gt;, it is also possible to query for information about a specific group, either by name or numeric id.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;grp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'admin'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getgrnam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Name    :'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'GID     :'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_gid&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Password:'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_passwd&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Members :'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;', '&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_mem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python grp_getgrnam.py&lt;br /&gt;Name    : admin&lt;br /&gt;GID     : 80&lt;br /&gt;Password: *&lt;br /&gt;Members : root, dhellmann&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="finding-a-group-by-id"&gt;&lt;h2&gt;Finding a Group by ID&lt;/h2&gt;&lt;p&gt;To identify the group running the current process, combine getgrgid() with os.getgid().&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;grp&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;gid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getgid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;group_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getgrgid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'Currently running with GID=&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; name=&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python grp_getgrgid_process.py&lt;br /&gt;Currently running with GID=501 name=dhellmann&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;And to get the group name based on the permissions on a file, look up the group returned by os.stat().&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;grp&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'grp_getgrgid_fileowner.py'&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;stat_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getgrgid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_gid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gr_name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; is owned by &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;)'&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stat_info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_gid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python grp_getgrgid_fileowner.py&lt;br /&gt;grp_getgrgid_fileowner.py is owned by dhellmann (501)&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="admonition-see-also admonition seealso"&gt;&lt;p class="first admonition-title"&gt;See also&lt;/p&gt;&lt;dl class="last docutils"&gt;&lt;dt&gt;&lt;a class="reference external" href="http://docs.python.org/library/grp.html"&gt;grp&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;The standard library documentation for this module.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;pwd&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Read user data from the password database.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;spwd&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Read user data from the shadow password database.&lt;/dd&gt;&lt;/dl&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.doughellmann.com/PyMOTW/"&gt;PyMOTW Home&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=uBQLmmIK"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?d=41" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=q1IcKOJa"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?d=50" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~f/doughellmann/python?a=EDlj9SK7"&gt;&lt;img src="http://feeds2.feedburner.com/~f/doughellmann/python?i=EDlj9SK7" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/doughellmann/python/~4/PbWWXcFLZuw" height="1" width="1" /&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/JtFMeZOk0-E" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.doughellmann.com/feeds/4694411690963470220/comments/default</feedburner:origLink></item>
			<item>
				<title>Embedding IronPython 2 and the Dynamic Language Runtime (turtles and articles)</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/i5y4TWRlEpM/arch_d7_2009_02_14.shtml</link>
				<pubDate>Mon, 16 Feb 2009 00:11:40 GMT</pubDate>
			<description>One of the most impressive things about DLR based languages like IronPython and IronRuby is how easy they are to host in applications to add dynamic features. You can even host IronPython in IronPython, something that Resolver One makes good use of to provide a separate execution context for each spreadsheet. ... [355 words]&lt;div class="feedflare"&gt;
&lt;a href="http://feeds2.feedburner.com/~f/voidspace?a=B6QPoXyQ"&gt;&lt;img src="http://feeds2.feedburner.com/~f/voidspace?i=B6QPoXyQ" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~f/voidspace?a=ylluoAFe"&gt;&lt;img src="http://feeds2.feedburner.com/~f/voidspace?i=ylluoAFe" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~f/voidspace?a=3dq9hTEu"&gt;&lt;img src="http://feeds2.feedburner.com/~f/voidspace?i=3dq9hTEu" border="0" /&gt;&lt;/a&gt; &lt;a href="http://feeds2.feedburner.com/~f/voidspace?a=osa7mdhP"&gt;&lt;img src="http://feeds2.feedburner.com/~f/voidspace?d=43" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds2.feedburner.com/~r/voidspace/~4/sEMXA2W1VGk" height="1" width="1" /&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/i5y4TWRlEpM" height="1" width="1"/&gt;</description><feedburner:origLink>http://feedproxy.google.com/~r/voidspace/~3/sEMXA2W1VGk/arch_d7_2009_02_14.shtml</feedburner:origLink></item>
			<item>
				<title>A better Caching system for Django</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/4fn3GE3dDsc/</link>
				<pubDate>Sun, 15 Feb 2009 21:55:14 GMT</pubDate>
			<description>&lt;p&gt;Django has &lt;em&gt;pretty good&lt;/em&gt; support for &lt;a title="Django Caching" href="http://docs.djangoproject.com/en/dev/topics/cache/#topics-cache"&gt;caching&lt;/a&gt;, which is one of the easiest ways of speeding up a web application. The default is to cache for ten minutes, which means that if you get multiple requests for a page within a ten minute window then Django can serve up a stored copy of the page without hitting the database or rendering the HTML. The caching period can be set per-page and fragments of pages can be cached rather than the whole, but the system rests on the fact that it doesn&amp;#8217;t matter if the content doesn&amp;#8217;t change for a period of time.&lt;/p&gt;
&lt;p&gt;Trouble is, not many web applications work that way. Consider a humble blog post with a piece of content and a list of comments. Granted, the post content isn&amp;#8217;t going to change very often and will probably never change again once the author has corrected all the typos, but a list of comments may change at any point through the life-time of the blog. If the page were cached, comments would not be visible on the page for a short period of time, which doesn&amp;#8217;t give that instant gratification that web users expect these days.&lt;/p&gt;
&lt;p&gt;It would be nice if a web app could benefit from caching and still serve a fresh page when content changes. Alas, Django&amp;#8217;s default time-based caching is never going to achieve this. What is needed is a way of invalidating an item in the cache when there are changes that alter the content; using the blog example, this would be when the post content changes or a new comment is submitted. Django does give you the tools to do this &amp;#8212; using the low &lt;a title="Django low level cache API" href="http://docs.djangoproject.com/en/dev/topics/cache/#the-low-level-cache-api"&gt;level cache API&lt;/a&gt;, you can construct a cache key (a simple string) that changes according to the page content, then store and retrieve your content manually. For example you might create a cache key with the modification date of the post, and the ID of the most recent comment. Then the page need only be rendered when the cache key isn&amp;#8217;t found in the cache. The downside of this approach is that it can take a little work to calculate the key (you may still have to hit the database to generate the cache key). This is not quite as nice as time-based caching, which will do negligible work for cached pages.&lt;/p&gt;
&lt;p&gt;A better approach, which has the benefit of always serving a fresh page, and still requires negligible work for cached pages is to construct the cache key based on the request, then invalidate (i.e. delete) the cache key when the content changes. Again, this can be done with Django, although it has no explicit support for it. Such a system requires more work because the web app must track any event that could potentially require a fresh page to be generated, but has the major advantage that up-to-date pages are virtually always going to be available in the cache.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve written ad-hoc page-event cache systems a couple of times and they are a major headache to maintain. Even on simple pages there can be multiple events that may invalidate a cached page. What would be nice, is some formal way of associating a model instance with a the URL(s) that depend on it, so that when the instance is saved, the associated pages will be invalidated and re-generated at the next request.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve not yet settled on the best way of implementing this, but it will probably be a decorator that builds up a mapping of object type plus primary key to its dependant URLs, and a &lt;em&gt;mixin&lt;/em&gt; for models that hooks in to the save method.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m open to suggestions regarding the most elegant implementation, and any other potential solutions!&lt;/p&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/4fn3GE3dDsc" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.willmcgugan.com/2009/02/15/a-better-caching-system-for-django/</feedburner:origLink></item>
			<item>
				<title>Bespin: code in the cloud</title>
				<link>http://feedproxy.google.com/~r/pythonlovers/~3/OpDQTyw2PAE/</link>
				<pubDate>Sun, 15 Feb 2009 10:30:19 GMT</pubDate>
			<description>&lt;p&gt;Despite working for an &lt;a href="http://www.mozilla.com/"&gt;open source company&lt;/a&gt;, I have been pretty quiet here about what I&amp;#8217;ve been doing in the Mozilla Labs web developer tools group. No more. We&amp;#8217;ve gone public!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://labs.mozilla.com/2009/02/introducing-bespin/"&gt;Mozilla Labs &amp;#187; Blog Archive &amp;#187; Introducing Bespin&lt;/a&gt;&lt;br /&gt;
&lt;blockquote&gt;Bespin proposes an open extensible web-based framework for code editing that aims to increase developer productivity, enable compelling user experiences, and promote the use of open standards.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I started working on Bespin as soon as I joined Mozilla, hitting the ground running with a new Python server. &lt;a href="http://www.ajaxian.com"&gt;Ben and Dion&lt;/a&gt; had already done a lot of work and experimentation on Bespin prior to joining Mozilla in December, so I must confess that I am still fairly ignorant about the Canvas-based magic that they&amp;#8217;re doing in the UI. But, Bespin has an architecture that lends itself well to selective ignorance: the server provides a &lt;a href="https://wiki.mozilla.org/BespinServerAPI"&gt;RESTful API&lt;/a&gt;, and the client is responsible for all of the presentation. For their part, Ben and Dion have been able to be blissfully ignorant about the inner workings of the Python server.&lt;/p&gt;
&lt;p&gt;Of course, I&amp;#8217;m not a JavaScript noob and have done some work in the client, but my focus has been the server. Now that we&amp;#8217;re out in the open, you can definitely expect that we&amp;#8217;ll be talking more about how things work and how you can bend Bespin to your will. Bespin is honest to goodness &lt;a href="http://hg.mozilla.org/labs/bespin/"&gt;open source&lt;/a&gt; (&lt;a href="http://www.mozilla.org/MPL/"&gt;MPL&lt;/a&gt;-licensed), so it becomes an open and collaborative effort starting right away.&lt;/p&gt;
&lt;p&gt;The initial reaction has been fantastic. There are tons of people hanging out in #bespin on irc.mozilla.org, and the &lt;a href="http://groups.google.com/group/bespin/"&gt;mailing list&lt;/a&gt; has grown to a couple hundred members already. Thanks to everyone for jumping in with your thoughts and patches!&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s some of the coverage:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ajaxian.com/archives/bespin-a-new-mozilla-labs-experimental-extensible-code-editor-using-canvas"&gt;Dion&amp;#8217;s post at Ajaxian&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ajaxian.com/wp-content/uploads/editorofourdreams.png" /&gt;&lt;/p&gt;
&lt;p&gt;From &lt;a href="http://almaer.com/blog/launching-bespin-feeling-light-as-a-cloud"&gt;Dion&amp;#8217;s personal blog&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;Foolish chaps and companies have come to me in the past thinking that open source will be a silver bullet for &amp;#8220;getting other people to do our work.&amp;#8221; Those that have been involved in open source know that it isn&amp;#8217;t the case. It is often more work. But, it is worth it.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;From &lt;a href="http://arstechnica.com/open-source/news/2009/02/ide-in-the-cloud-mozilla-labs-browser-based-ide-prototype.ars"&gt;Ars Technica&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;The project is still at an early stage of development and there is clearly a lot of work to be done before it will be able to deliver the same practical value as existing desktop editors. Despite the limitations, it shows an enormous amount of promise and has the potential to eventually deliver a user experience that rivals even the best text editors.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;From &lt;a href="http://opensourcereleasefeed.com/interview/show/five-questions-with-dion-almaer-co-creator-of-mozilla-bespin"&gt;Five Questions with Dion Almaer&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;Now the browsers are moving fast again   and building a first class platform for us to develop, the Open Web Platform. Instead of getting bogged down thinking about   what IE 6 gives you, take some time to think about what you could build with the latest technology. I realise that you have to   be pragmatic and get things working with your audience, but browsers are changing, and so are expectations.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;From &lt;a href="http://www.computerworlduk.com/community/blogs/index.cfm?entryid=1858&amp;amp;blogid=14"&gt;What Mozilla&amp;#8217;s Bespin Bespeaks&lt;/a&gt; (ComputerworldUK):&lt;br /&gt;
&lt;blockquote&gt;You can see that Bespin is ticking all the Mozilla boxes, but what&amp;#8217;s also striking is that this is a Web-based project: Mozilla is entering the cloud. It&amp;#8217;s a further shift to viewing the Web as a platform for doing, well, just about anything. Clearly, against that background, open standards are even more important. And not only for the code: another issue that Mozilla will need to start addressing publicly is that of open data. As more stuff moves into the cloud, it become imperative to establish minimum standards for access to the data that is held there. I look forward to hearing Mozilla&amp;#8217;s views on the subject. &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;While I certainly don&amp;#8217;t speak for Mozilla, I would be &lt;i&gt;extremely surprised&lt;/i&gt; if there&amp;#8217;s anyone at Mozilla that believes that users should have anything less than full access and ability to take their data with them. There can be technical issues involved in providing the data, but the data should be available in some reasonable form. Bespin, for its part, makes it easy to export a project in a tarball or zipfile.&lt;/p&gt;
&lt;p&gt;I was surprised to see &lt;a href="http://lifehacker.com/5152999/mozilla-bespin-is-a-killer-web+based-text-editor"&gt;Bespin covered even on Lifehacker&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;Primarily, Bespin is a text editor&amp;#8212;the kind you&amp;#8217;d use for editing code or managing &lt;a href="http://lifehacker.com/software/text/geek-to-live-list-your-life-in-txt-166299.php"&gt;text-based todos&lt;/a&gt;. Using Bespin, developers could collaborate on projects through a unified interface (that still supports plugins!) no matter where they are&amp;#8212;so long as they&amp;#8217;ve got a browser.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://news.cnet.com/8301-17939_109-10163516-2.html"&gt;cnet has the story,&lt;/a&gt; too:&lt;br /&gt;
&lt;blockquote&gt;For example, what about integration with open-source software repositories? If it&amp;#8217;s flexible enough, Bespin could essentially act as a source code viewer that repositories such as SourceForge or Google Code could employ. &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;A &lt;a href="http://www.readwriteweb.com/archives/bespin_html_editor_cloud.php"&gt;nice writeup on the ReadWriteWeb&lt;/a&gt; as well:&lt;br /&gt;
&lt;blockquote&gt;It&amp;#8217;s clear that a great deal of thought and attention went into this early version - and it&amp;#8217;s a safe bet that it will only get more impressive as time goes on.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;RWW last month surprised me with &lt;a href="http://www.readwriteweb.com/jobwire/2009/01/mozilla-developer-tools-lab-hi.php"&gt;their coverage of me joining Mozilla&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m having a great time at Mozilla so far, and it&amp;#8217;s great to be out in the open working with so many people now on Bespin and &lt;a href="http://groups.google.com/group/serverjs"&gt;ServerJS&lt;/a&gt;.&lt;/p&gt;
&lt;div class="zemanta-pixie"&gt;&lt;img class="zemanta-pixie-img" src="http://img.zemanta.com/pixy.gif?x-id=da16a7ba-73bb-4ac9-83a3-f954ff3f2b0c" /&gt;&lt;/div&gt;			
			
			&lt;br/&gt;
			&lt;script type="text/javascript"&gt;&lt;!--
				google_ad_client = "pub-1411256716541452";
				google_ad_width = 468;
				google_ad_height = 15;
				google_ad_format = "468x15_0ads_al";
				google_ad_channel = "";
				google_color_border = "FFFFFF";
				google_color_bg = "FFFFFF";
				google_color_link = "2D8930";
				google_color_text = "000000";
				google_color_url = "008000";
				//--&gt;
			&lt;/script&gt;
			&lt;script type="text/javascript"
				src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
			&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/pythonlovers/~4/OpDQTyw2PAE" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.blueskyonmars.com/2009/02/14/bespin-code-in-the-cloud/</feedburner:origLink></item></channel></rss>
