<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.doughellmann.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-5440028356946346379</id><updated>2010-03-14T10:58:47.966-04:00</updated><title type="text">Doug Hellmann</title><subtitle type="html">&lt;p&gt;Code Interstices&lt;/p&gt;

&lt;p&gt;All the little things that happen between bouts of coding.  Covering internet technologies, Python, Mac OS X, and open source.&lt;/p&gt;</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.doughellmann.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.doughellmann.com/search/label/PyMOTW" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/-/PyMOTW/-/PyMOTW?start-index=5&amp;max-results=4" /><author><name>Doug Hellmann</name><uri>http://www.blogger.com/profile/01892352754222143463</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>148</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>4</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.doughellmann.com/PyMOTW" /><feedburner:info uri="pymotw" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>PyMOTW</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry><id>tag:blogger.com,1999:blog-5440028356946346379.post-2248271756635298269</id><published>2010-03-14T10:58:00.001-04:00</published><updated>2010-03-14T10:58:48.055-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="PyMOTW" /><title type="text">PyMOTW: Parsing XML Documents with ElementTree</title><content type="html">&lt;div class="section" id="parsing-xml-documents-with-elementtree"&gt;&lt;span id="xml-etree-elementtree-parsing"&gt;&lt;/span&gt;&lt;h1&gt;Parsing XML Documents with ElementTree&lt;/h1&gt;&lt;p&gt;Parsed XML documents are represented in memory by ElementTree and&lt;br /&gt;Element objects connected into a tree structure based on the way the&lt;br /&gt;nodes in the XML document are nested.&lt;/p&gt;&lt;div class="section" id="parsing-an-entire-document"&gt;&lt;h2&gt;Parsing an Entire Document&lt;/h2&gt;&lt;p&gt;When you parse an entire document with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;parse()&lt;/span&gt;&lt;/tt&gt;, an ElementTree&lt;br /&gt;instance is returned.  The tree knows about all of the data in the&lt;br /&gt;input document, and the nodes of the tree can be searched or&lt;br /&gt;manipulated in place.  While this flexibility can make working with&lt;br /&gt;the parsed document a little easier, it typically takes more memory&lt;br /&gt;than an event-based parsing approach since the entire document must be&lt;br /&gt;loaded at one time.&lt;/p&gt;&lt;p&gt;The memory footprint of small, simple documents such as this list of&lt;br /&gt;podcasts represented as an &lt;a class="reference external" href="http://www.opml.org/"&gt;OPML&lt;/a&gt; outline is not significant:&lt;/p&gt;&lt;div class="highlight-xml"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;opml&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Podcasts&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;dateCreated&amp;gt;&lt;/span&gt;Sun, 07 Mar 2010 15:53:26 GMT&lt;span class="nt"&gt;&amp;lt;/dateCreated&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;dateModified&amp;gt;&lt;/span&gt;Sun, 07 Mar 2010 15:53:26 GMT&lt;span class="nt"&gt;&amp;lt;/dateModified&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Science and Tech&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;APM: Future Tense&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.publicradio.org/columns/futuretense/podcast.xml&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.publicradio.org/columns/futuretense/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Engines Of Our Ingenuity Podcast&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.npr.org/rss/podcast.php?id=510030&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.uh.edu/engines/engines.htm&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Science &amp;amp;#38; the City&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.nyas.org/Podcasts/Atom.axd&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.nyas.org/WhatWeDo/SciencetheCity.aspx&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;/outline&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Books and Fiction&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Podiobooker&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://feeds.feedburner.com/podiobooks&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.podiobooks.com/blog&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;The Drabblecast&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://web.me.com/normsherman/Site/Podcast/rss.xml&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://web.me.com/normsherman/Site/Podcast/Podcast.html&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tor.com / category / tordotstories&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.tor.com/rss/category/TorDotStories&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.tor.com/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;/outline&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Computers and Programming&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;MacBreak Weekly&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://leo.am/podcasts/mbw&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://twit.tv/mbw&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;FLOSS Weekly&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://leo.am/podcasts/floss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://twit.tv&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Core Intuition&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.coreint.org/podcast.xml&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.coreint.org/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;/outline&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Python&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PyCon Podcast&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://advocacy.python.org/podcasts/pycon.rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://advocacy.python.org/podcasts/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A Little Bit of Python&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://advocacy.python.org/podcasts/littlebit.rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://advocacy.python.org/podcasts/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Django Dose Everything Feed&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://djangodose.com/everything/feed/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;/outline&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Miscelaneous&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;outline&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dhellmann&amp;#39;s CastSampler Feed&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rss&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;xmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.castsampler.com/cast/feed/rss/dhellmann/&amp;quot;&lt;/span&gt; &lt;br /&gt;             &lt;span class="na"&gt;htmlUrl=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.castsampler.com/users/dhellmann/&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;/outline&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;/opml&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;To parse the file, pass an open file handle to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;parse()&lt;/span&gt;&lt;/tt&gt;.  It will&lt;br /&gt;read the data, parse the XML, and return an ElementTree object.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;tree&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 ElementTree_parse_opml.py&lt;br /&gt;&amp;lt;xml.etree.ElementTree.ElementTree instance at 0x82f58&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="traversing-the-parsed-tree"&gt;&lt;h2&gt;Traversing the Parsed Tree&lt;/h2&gt;&lt;p&gt;Now that we have a parsed XML tree, we can iterate over it, visiting&lt;br /&gt;all of the children in order and examining their attributes and&lt;br /&gt;contents.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getiterator&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;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here we print the entire tree, one tag at a time.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_dump_opml.py&lt;br /&gt;opml {'version': '1.0'}&lt;br /&gt;head {}&lt;br /&gt;title {}&lt;br /&gt;dateCreated {}&lt;br /&gt;dateModified {}&lt;br /&gt;body {}&lt;br /&gt;outline {'text': 'Science and Tech'}&lt;br /&gt;outline {'xmlUrl': 'http://www.publicradio.org/columns/futuretense/podcast.xml', 'text': 'APM: Future Tense', 'type': 'rss', 'htmlUrl': 'http://www.publicradio.org/columns/futuretense/'}&lt;br /&gt;outline {'xmlUrl': 'http://www.npr.org/rss/podcast.php?id=510030', 'text': 'Engines Of Our Ingenuity Podcast', 'type': 'rss', 'htmlUrl': 'http://www.uh.edu/engines/engines.htm'}&lt;br /&gt;outline {'xmlUrl': 'http://www.nyas.org/Podcasts/Atom.axd', 'text': 'Science &amp;amp; the City', 'type': 'rss', 'htmlUrl': 'http://www.nyas.org/WhatWeDo/SciencetheCity.aspx'}&lt;br /&gt;outline {'text': 'Books and Fiction'}&lt;br /&gt;outline {'xmlUrl': 'http://feeds.feedburner.com/podiobooks', 'text': 'Podiobooker', 'type': 'rss', 'htmlUrl': 'http://www.podiobooks.com/blog'}&lt;br /&gt;outline {'xmlUrl': 'http://web.me.com/normsherman/Site/Podcast/rss.xml', 'text': 'The Drabblecast', 'type': 'rss', 'htmlUrl': 'http://web.me.com/normsherman/Site/Podcast/Podcast.html'}&lt;br /&gt;outline {'xmlUrl': 'http://www.tor.com/rss/category/TorDotStories', 'text': 'tor.com / category / tordotstories', 'type': 'rss', 'htmlUrl': 'http://www.tor.com/'}&lt;br /&gt;outline {'text': 'Computers and Programming'}&lt;br /&gt;outline {'xmlUrl': 'http://leo.am/podcasts/mbw', 'text': 'MacBreak Weekly', 'type': 'rss', 'htmlUrl': 'http://twit.tv/mbw'}&lt;br /&gt;outline {'xmlUrl': 'http://leo.am/podcasts/floss', 'text': 'FLOSS Weekly', 'type': 'rss', 'htmlUrl': 'http://twit.tv'}&lt;br /&gt;outline {'xmlUrl': 'http://www.coreint.org/podcast.xml', 'text': 'Core Intuition', 'type': 'rss', 'htmlUrl': 'http://www.coreint.org/'}&lt;br /&gt;outline {'text': 'Python'}&lt;br /&gt;outline {'xmlUrl': 'http://advocacy.python.org/podcasts/pycon.rss', 'text': 'PyCon Podcast', 'type': 'rss', 'htmlUrl': 'http://advocacy.python.org/podcasts/'}&lt;br /&gt;outline {'xmlUrl': 'http://advocacy.python.org/podcasts/littlebit.rss', 'text': 'A Little Bit of Python', 'type': 'rss', 'htmlUrl': 'http://advocacy.python.org/podcasts/'}&lt;br /&gt;outline {'xmlUrl': 'http://djangodose.com/everything/feed/', 'text': 'Django Dose Everything Feed', 'type': 'rss'}&lt;br /&gt;outline {'text': 'Miscelaneous'}&lt;br /&gt;outline {'xmlUrl': 'http://www.castsampler.com/cast/feed/rss/dhellmann/', 'text': "dhellmann's CastSampler Feed", 'type': 'rss', 'htmlUrl': 'http://www.castsampler.com/users/dhellmann/'}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;If we wanted to print only the groups of names and feed URLs for the&lt;br /&gt;podcasts, leaving out of all of the data in the header section, we&lt;br /&gt;could iterate over only just the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;outline&lt;/span&gt;&lt;/tt&gt; nodes and print the&lt;br /&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;text&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;xmlUrl&lt;/span&gt;&lt;/tt&gt; attributes.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getiterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;outline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;url&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;&amp;#39;  &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;&amp;#39;&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&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&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;name&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Because we passed &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;'outline'&lt;/span&gt;&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;tree.getiterator()&lt;/span&gt;&lt;/tt&gt; processing is&lt;br /&gt;limited to only nodes with the tag &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;'outline'&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_show_feed_urls.py&lt;br /&gt;Science and Tech&lt;br /&gt;  APM: Future Tense :: http://www.publicradio.org/columns/futuretense/podcast.xml&lt;br /&gt;  Engines Of Our Ingenuity Podcast :: http://www.npr.org/rss/podcast.php?id=510030&lt;br /&gt;  Science &amp;amp; the City :: http://www.nyas.org/Podcasts/Atom.axd&lt;br /&gt;Books and Fiction&lt;br /&gt;  Podiobooker :: http://feeds.feedburner.com/podiobooks&lt;br /&gt;  The Drabblecast :: http://web.me.com/normsherman/Site/Podcast/rss.xml&lt;br /&gt;  tor.com / category / tordotstories :: http://www.tor.com/rss/category/TorDotStories&lt;br /&gt;Computers and Programming&lt;br /&gt;  MacBreak Weekly :: http://leo.am/podcasts/mbw&lt;br /&gt;  FLOSS Weekly :: http://leo.am/podcasts/floss&lt;br /&gt;  Core Intuition :: http://www.coreint.org/podcast.xml&lt;br /&gt;Python&lt;br /&gt;  PyCon Podcast :: http://advocacy.python.org/podcasts/pycon.rss&lt;br /&gt;  A Little Bit of Python :: http://advocacy.python.org/podcasts/littlebit.rss&lt;br /&gt;  Django Dose Everything Feed :: http://djangodose.com/everything/feed/&lt;br /&gt;Miscelaneous&lt;br /&gt;  dhellmann's CastSampler Feed :: http://www.castsampler.com/cast/feed/rss/dhellmann/&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="finding-nodes-in-a-document"&gt;&lt;h2&gt;Finding Nodes in a Document&lt;/h2&gt;&lt;p&gt;Walking the entire tree yourself like this searching for relevant&lt;br /&gt;nodes can be error prone.  In the example above, we had to look at&lt;br /&gt;each outline node to determine if it was a group (nodes with only a&lt;br /&gt;&amp;#8220;text&amp;#8221; attribute) or podcast (with both &amp;#8220;text&amp;#8221; and &amp;#8220;xmlUrl&amp;#8221;).  If we&lt;br /&gt;were writing a podcast downloader and needed to produce a simple list&lt;br /&gt;of the podcast feed URLs, without names or groups, we might simplify&lt;br /&gt;the logic using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;findall()&lt;/span&gt;&lt;/tt&gt; to look for nodes with more descriptive&lt;br /&gt;search characteristics.&lt;/p&gt;&lt;p&gt;A first pass at converting the above example might construct an XPath&lt;br /&gt;argument to look for all outline nodes.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;.//outline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;url&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;url&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The logic in this version is not substantially different than the&lt;br /&gt;version using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;getiterator()&lt;/span&gt;&lt;/tt&gt;.  We still have to check for the&lt;br /&gt;presence of the URL, except that we don&amp;#8217;t print the group name when&lt;br /&gt;the URL is not found.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_find_feeds_by_tag.py&lt;br /&gt;http://www.publicradio.org/columns/futuretense/podcast.xml&lt;br /&gt;http://www.npr.org/rss/podcast.php?id=510030&lt;br /&gt;http://www.nyas.org/Podcasts/Atom.axd&lt;br /&gt;http://feeds.feedburner.com/podiobooks&lt;br /&gt;http://web.me.com/normsherman/Site/Podcast/rss.xml&lt;br /&gt;http://www.tor.com/rss/category/TorDotStories&lt;br /&gt;http://leo.am/podcasts/mbw&lt;br /&gt;http://leo.am/podcasts/floss&lt;br /&gt;http://www.coreint.org/podcast.xml&lt;br /&gt;http://advocacy.python.org/podcasts/pycon.rss&lt;br /&gt;http://advocacy.python.org/podcasts/littlebit.rss&lt;br /&gt;http://djangodose.com/everything/feed/&lt;br /&gt;http://www.castsampler.com/cast/feed/rss/dhellmann/&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Another version can take advantage of the fact that we know the&lt;br /&gt;outline nodes are only nested two levels deep.  If we change the&lt;br /&gt;search path to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;.//outline/outline&lt;/span&gt;&lt;/tt&gt; we will process only the second&lt;br /&gt;level of outline nodes.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;.//outline/outline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&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;url&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;We expect all of those outline nodes nested 2 levels deep in the input&lt;br /&gt;will have the xmlURL attribute refering to the podcast feed, so if we&lt;br /&gt;were brave we could skip checking for for the attribute before using&lt;br /&gt;it.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_find_feeds_by_structure.py&lt;br /&gt;http://www.publicradio.org/columns/futuretense/podcast.xml&lt;br /&gt;http://www.npr.org/rss/podcast.php?id=510030&lt;br /&gt;http://www.nyas.org/Podcasts/Atom.axd&lt;br /&gt;http://feeds.feedburner.com/podiobooks&lt;br /&gt;http://web.me.com/normsherman/Site/Podcast/rss.xml&lt;br /&gt;http://www.tor.com/rss/category/TorDotStories&lt;br /&gt;http://leo.am/podcasts/mbw&lt;br /&gt;http://leo.am/podcasts/floss&lt;br /&gt;http://www.coreint.org/podcast.xml&lt;br /&gt;http://advocacy.python.org/podcasts/pycon.rss&lt;br /&gt;http://advocacy.python.org/podcasts/littlebit.rss&lt;br /&gt;http://djangodose.com/everything/feed/&lt;br /&gt;http://www.castsampler.com/cast/feed/rss/dhellmann/&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;This version is limited to our existing structure, though, so if the&lt;br /&gt;outline nodes are ever rearranged into a deeper tree it will stop&lt;br /&gt;working.&lt;/p&gt;&lt;/div&gt;&lt;div class="section" id="parsed-node-attributes"&gt;&lt;h2&gt;Parsed Node Attributes&lt;/h2&gt;&lt;p&gt;The items returned by &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;findall()&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;getiterator()&lt;/span&gt;&lt;/tt&gt; are Element&lt;br /&gt;objects, each representing a node in the XML parse tree.  Each Element&lt;br /&gt;has attributes for accessing data pulled out of the XML.  This can be&lt;br /&gt;illustrated with a somewhat more contrived example input file,&lt;br /&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;data.xml&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;&lt;div class="highlight-xml"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;br /&gt;2&lt;br /&gt;3&lt;br /&gt;4&lt;br /&gt;5&lt;br /&gt;6&lt;br /&gt;7&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;top&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;child&amp;gt;&lt;/span&gt;This child contains text.&lt;span class="nt"&gt;&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;child_with_tail&amp;gt;&lt;/span&gt;This child has regular text.&lt;span class="nt"&gt;&amp;lt;/child_with_tail&amp;gt;&lt;/span&gt;And &amp;quot;tail&amp;quot; text.&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;with_attributes&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;foo=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="nt"&gt;&amp;lt;entity_expansion&lt;/span&gt; &lt;span class="na"&gt;attribute=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;This &amp;amp;#38; That&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;That &lt;span class="ni"&gt;&amp;amp;#38;&lt;/span&gt; This&lt;span class="nt"&gt;&amp;lt;/entity_expansion&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;/top&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;The &amp;#8220;attributes&amp;#8221; of a node are available in the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;attrib&lt;/span&gt;&lt;/tt&gt; property,&lt;br /&gt;which acts like a dictionary.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;data.xml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;./with_attributes&amp;#39;&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;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;for&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;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&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;&amp;#39;  &lt;/span&gt;&lt;span class="si"&gt;%-4s&lt;/span&gt;&lt;span class="s"&gt; = &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;&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&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The node on line 5 of the input file has 2 attributes, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;name&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;foo&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_node_attributes.py&lt;br /&gt;with_attributes&lt;br /&gt;  foo  = "bar"&lt;br /&gt;  name = "value"&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;The text content of the nodes is available, along with the &amp;#8220;tail&amp;#8221; text&lt;br /&gt;that comes after the end of a close tag.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;data.xml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;path&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;&amp;#39;./child&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;./child_with_tail&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;  child node text:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;  and tail text  :&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;child&lt;/span&gt;&lt;/tt&gt; node on line 3 contains embedded text, and the node on&lt;br /&gt;line 4 has text with a tail (including any whitespace).&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_node_text.py&lt;br /&gt;child&lt;br /&gt;  child node text: This child contains text.&lt;br /&gt;  and tail text  :&lt;br /&gt;&lt;br /&gt;child_with_tail&lt;br /&gt;  child node text: This child has regular text.&lt;br /&gt;  and tail text  : And "tail" text.&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Conveniently, XML entity references embedded in the document are&lt;br /&gt;converted to the appropriate characters before values are returned.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;data.xml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entity_expansion&amp;#39;&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;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;  in attribute:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;attribute&amp;#39;&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;&amp;#39;  in text     :&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The conversion saves you from having to worry about an implementation&lt;br /&gt;detail of representing certain characters in an XML document.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_entity_references.py&lt;br /&gt;entity_expansion&lt;br /&gt;  in attribute: This &amp;amp; That&lt;br /&gt;  in text     : That &amp;amp; This&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="watching-events-while-parsing"&gt;&lt;h2&gt;Watching Events While Parsing&lt;/h2&gt;&lt;p&gt;The other API useful for processing XML documents is event-based.  The&lt;br /&gt;parser generates &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;start&lt;/span&gt;&lt;/tt&gt; events for opening tags and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;end&lt;/span&gt;&lt;/tt&gt; events&lt;br /&gt;for closing tags.  Iterating over the event stream lets you extract&lt;br /&gt;data from the document while parsing it, which is convenient if you&lt;br /&gt;don&amp;#8217;t need to manipulate the entire document afterwards and if you&lt;br /&gt;want to avoid holding the entire parsed document in memory.&lt;/p&gt;&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;iterparse()&lt;/span&gt;&lt;/tt&gt; returns an iterable that produces tuples containing&lt;br /&gt;the name of the event and the node triggering the event.  Events can&lt;br /&gt;be one of:&lt;/p&gt;&lt;dl class="docutils"&gt;&lt;dt&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;start&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;A new tag has been encountered.  The closing angle bracket of the&lt;br /&gt;tag was processed, but not the contents.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;end&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;The closing angle bracket of a closing tag has been processed.  All&lt;br /&gt;of the children were already processed.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;start-ns&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Start a namespace declaration.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;end-ns&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;End a namespace declaration.&lt;/dd&gt;&lt;/dl&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;iterparse&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;prefix_width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;prefix_dots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;prefix_width&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;line_template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;{prefix:&amp;lt;0.{prefix_len}}{event:&amp;lt;8}{suffix:&amp;lt;{suffix_len}} {node.tag:&amp;lt;12} {node_id}&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;iterparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;start&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;end&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;start-ns&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;end-ns&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;end&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="n"&gt;prefix_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;line_template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prefix_dots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                               &lt;span class="n"&gt;prefix_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prefix_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                               &lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                               &lt;span class="n"&gt;suffix_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix_width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;prefix_len&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;                               &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;                               &lt;span class="n"&gt;node_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;                               &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&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;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;start&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;By default, only &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;end&lt;/span&gt;&lt;/tt&gt; events are generated.  To see other events,&lt;br /&gt;pass the list of event names you want to receive to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;iterparse()&lt;/span&gt;&lt;/tt&gt;,&lt;br /&gt;as in this example:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_show_all_events.py&lt;br /&gt;start            opml         876256&lt;br /&gt;..start          head         876336&lt;br /&gt;....start        title        888920&lt;br /&gt;....end          title        888920&lt;br /&gt;....start        dateCreated  889280&lt;br /&gt;....end          dateCreated  889280&lt;br /&gt;....start        dateModified 889320&lt;br /&gt;....end          dateModified 889320&lt;br /&gt;..end            head         876336&lt;br /&gt;..start          body         889400&lt;br /&gt;....start        outline      889560&lt;br /&gt;......start      outline      889600&lt;br /&gt;......end        outline      889600&lt;br /&gt;......start      outline      889480&lt;br /&gt;......end        outline      889480&lt;br /&gt;......start      outline      889680&lt;br /&gt;......end        outline      889680&lt;br /&gt;....end          outline      889560&lt;br /&gt;....start        outline      889720&lt;br /&gt;......start      outline      889760&lt;br /&gt;......end        outline      889760&lt;br /&gt;......start      outline      889840&lt;br /&gt;......end        outline      889840&lt;br /&gt;......start      outline      889920&lt;br /&gt;......end        outline      889920&lt;br /&gt;....end          outline      889720&lt;br /&gt;....start        outline      889880&lt;br /&gt;......start      outline      890040&lt;br /&gt;......end        outline      890040&lt;br /&gt;......start      outline      890120&lt;br /&gt;......end        outline      890120&lt;br /&gt;......start      outline      890200&lt;br /&gt;......end        outline      890200&lt;br /&gt;....end          outline      889880&lt;br /&gt;....start        outline      890240&lt;br /&gt;......start      outline      890360&lt;br /&gt;......end        outline      890360&lt;br /&gt;......start      outline      890440&lt;br /&gt;......end        outline      890440&lt;br /&gt;......start      outline      890520&lt;br /&gt;......end        outline      890520&lt;br /&gt;....end          outline      890240&lt;br /&gt;....start        outline      890640&lt;br /&gt;......start      outline      890720&lt;br /&gt;......end        outline      890720&lt;br /&gt;....end          outline      890640&lt;br /&gt;..end            body         889400&lt;br /&gt;end              opml         876256&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;The event-style of processing may be more natural for some operations,&lt;br /&gt;such as converting XML input to some other format.  For example,&lt;br /&gt;suppose we want to convert the list of podcasts we have been working&lt;br /&gt;with from an XML file to a data file we can load into a spreadsheet or&lt;br /&gt;database application.  We don&amp;#8217;t need to hold the entire data set in&lt;br /&gt;memory at a time, since we&amp;#8217;re simply changing the format.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;csv&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;iterparse&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&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;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quoting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUOTE_NONNUMERIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;group_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;iterparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;start&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;outline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="c"&gt;# Ignore anything not part of the outline&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;continue&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;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="c"&gt;# Remember the current group&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;group_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&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="c"&gt;# Output a podcast entry&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;br /&gt;                          &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;br /&gt;                          &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;htmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&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="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This example program converts our podcast list to a CSV file, ready to&lt;br /&gt;be imported into another application.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_write_podcast_csv.py&lt;br /&gt;"Science and Tech","APM: Future Tense","http://www.publicradio.org/columns/futuretense/podcast.xml","http://www.publicradio.org/columns/futuretense/"&lt;br /&gt;"Science and Tech","Engines Of Our Ingenuity Podcast","http://www.npr.org/rss/podcast.php?id=510030","http://www.uh.edu/engines/engines.htm"&lt;br /&gt;"Science and Tech","Science &amp;amp; the City","http://www.nyas.org/Podcasts/Atom.axd","http://www.nyas.org/WhatWeDo/SciencetheCity.aspx"&lt;br /&gt;"Books and Fiction","Podiobooker","http://feeds.feedburner.com/podiobooks","http://www.podiobooks.com/blog"&lt;br /&gt;"Books and Fiction","The Drabblecast","http://web.me.com/normsherman/Site/Podcast/rss.xml","http://web.me.com/normsherman/Site/Podcast/Podcast.html"&lt;br /&gt;"Books and Fiction","tor.com / category / tordotstories","http://www.tor.com/rss/category/TorDotStories","http://www.tor.com/"&lt;br /&gt;"Computers and Programming","MacBreak Weekly","http://leo.am/podcasts/mbw","http://twit.tv/mbw"&lt;br /&gt;"Computers and Programming","FLOSS Weekly","http://leo.am/podcasts/floss","http://twit.tv"&lt;br /&gt;"Computers and Programming","Core Intuition","http://www.coreint.org/podcast.xml","http://www.coreint.org/"&lt;br /&gt;"Python","PyCon Podcast","http://advocacy.python.org/podcasts/pycon.rss","http://advocacy.python.org/podcasts/"&lt;br /&gt;"Python","A Little Bit of Python","http://advocacy.python.org/podcasts/littlebit.rss","http://advocacy.python.org/podcasts/"&lt;br /&gt;"Python","Django Dose Everything Feed","http://djangodose.com/everything/feed/",""&lt;br /&gt;"Miscelaneous","dhellmann's CastSampler Feed","http://www.castsampler.com/cast/feed/rss/dhellmann/","http://www.castsampler.com/users/dhellmann/"&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="creating-your-own-tree-builder"&gt;&lt;h2&gt;Creating Your Own Tree Builder&lt;/h2&gt;&lt;p&gt;A potentially more efficient means of handling parse events is to&lt;br /&gt;replace the standard tree builder behavior with your own.  The&lt;br /&gt;ElementTree parser uses an XMLTreeBuilder to process the XML and call&lt;br /&gt;methods on a target class to save the results.  The usual output is an&lt;br /&gt;ElementTree instance created by the default TreeBuilder class.  By&lt;br /&gt;replacing TreeBuilder with your own class, you can receive the events&lt;br /&gt;before the Element nodes are instantiated, saving that portion of the&lt;br /&gt;overhead.&lt;/p&gt;&lt;p&gt;The XML-to-CSV app from the previous section can be translated to a&lt;br /&gt;tree builder.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;csv&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLTreeBuilder&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PodcastListToCSV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quoting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUOTE_NONNUMERIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;outline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;            &lt;span class="c"&gt;# Ignore anything not part of the outline&lt;/span&gt;&lt;br /&gt;            &lt;span class="k"&gt;return&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;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;            &lt;span class="c"&gt;# Remember the current group&lt;/span&gt;&lt;br /&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&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="c"&gt;# Output a podcast entry&lt;/span&gt;&lt;br /&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;br /&gt;                                   &lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;br /&gt;                                   &lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;htmlUrl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&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="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="c"&gt;# Ignore closing tags&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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="c"&gt;# Ignore data inside nodes&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="c"&gt;# Nothing special to do here&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PodcastListToCSV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLTreeBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;podcasts.opml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;rt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&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;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;        &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;parser&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;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;PodcastListToCSV&lt;/span&gt;&lt;/tt&gt; implements the TreeBuilder protocol.  Each time a&lt;br /&gt;new XML tag is encountered, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;start()&lt;/span&gt;&lt;/tt&gt; is called with the tag name&lt;br /&gt;and attributes.  When a closing tag is seen &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;end()&lt;/span&gt;&lt;/tt&gt; is called with&lt;br /&gt;the name.  In between, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;data()&lt;/span&gt;&lt;/tt&gt; is called when a node has content&lt;br /&gt;(the tree builder is expected to keep up with the &amp;#8220;current&amp;#8221; node).&lt;br /&gt;When all of the input is processed, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;close()&lt;/span&gt;&lt;/tt&gt; is called.  It can&lt;br /&gt;return a value, which will be returned to the user of the&lt;br /&gt;XMLTreeBuilder.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_podcast_csv_treebuilder.py&lt;br /&gt;"Science and Tech","APM: Future Tense","http://www.publicradio.org/columns/futuretense/podcast.xml","http://www.publicradio.org/columns/futuretense/"&lt;br /&gt;"Science and Tech","Engines Of Our Ingenuity Podcast","http://www.npr.org/rss/podcast.php?id=510030","http://www.uh.edu/engines/engines.htm"&lt;br /&gt;"Science and Tech","Science &amp;amp; the City","http://www.nyas.org/Podcasts/Atom.axd","http://www.nyas.org/WhatWeDo/SciencetheCity.aspx"&lt;br /&gt;"Books and Fiction","Podiobooker","http://feeds.feedburner.com/podiobooks","http://www.podiobooks.com/blog"&lt;br /&gt;"Books and Fiction","The Drabblecast","http://web.me.com/normsherman/Site/Podcast/rss.xml","http://web.me.com/normsherman/Site/Podcast/Podcast.html"&lt;br /&gt;"Books and Fiction","tor.com / category / tordotstories","http://www.tor.com/rss/category/TorDotStories","http://www.tor.com/"&lt;br /&gt;"Computers and Programming","MacBreak Weekly","http://leo.am/podcasts/mbw","http://twit.tv/mbw"&lt;br /&gt;"Computers and Programming","FLOSS Weekly","http://leo.am/podcasts/floss","http://twit.tv"&lt;br /&gt;"Computers and Programming","Core Intuition","http://www.coreint.org/podcast.xml","http://www.coreint.org/"&lt;br /&gt;"Python","PyCon Podcast","http://advocacy.python.org/podcasts/pycon.rss","http://advocacy.python.org/podcasts/"&lt;br /&gt;"Python","A Little Bit of Python","http://advocacy.python.org/podcasts/littlebit.rss","http://advocacy.python.org/podcasts/"&lt;br /&gt;"Python","Django Dose Everything Feed","http://djangodose.com/everything/feed/",""&lt;br /&gt;"Miscelaneous","dhellmann's CastSampler Feed","http://www.castsampler.com/cast/feed/rss/dhellmann/","http://www.castsampler.com/users/dhellmann/"&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="parsing-strings"&gt;&lt;h2&gt;Parsing Strings&lt;/h2&gt;&lt;p&gt;To work with smaller bits of XML text, especially string literals as&lt;br /&gt;might be embedded in the source of a program, use&lt;br /&gt;xml.etree.ElementTree.XML and pass a single argument, the string&lt;br /&gt;containing the XML to be parsed.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XML&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;root&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;    &amp;lt;child id=&amp;quot;a&amp;quot;&amp;gt;This is child &amp;quot;a&amp;quot;.&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;    &amp;lt;child id=&amp;quot;b&amp;quot;&amp;gt;This is child &amp;quot;b&amp;quot;.&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;/group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;    &amp;lt;child id=&amp;quot;c&amp;quot;&amp;gt;This is child &amp;quot;c&amp;quot;.&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;/group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;&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;&amp;#39;parsed =&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getiterator&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;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&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;&amp;#39;  text: &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&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;&amp;#39;  tail: &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;for&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;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&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;&amp;#39;  &lt;/span&gt;&lt;span class="si"&gt;%-4s&lt;/span&gt;&lt;span class="s"&gt; = &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;&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&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&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;p&gt;Notice that unlike with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;parse()&lt;/span&gt;&lt;/tt&gt;, the return value is an Element&lt;br /&gt;instance instead of an ElementTree.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_XML.py&lt;br /&gt;parsed = &amp;lt;Element root at d4e40&amp;gt;&lt;br /&gt;root&lt;br /&gt;&lt;br /&gt;group&lt;br /&gt;&lt;br /&gt;child&lt;br /&gt;  text: "This is child "a"."&lt;br /&gt;  id   = "a"&lt;br /&gt;&lt;br /&gt;child&lt;br /&gt;  text: "This is child "b"."&lt;br /&gt;  id   = "b"&lt;br /&gt;&lt;br /&gt;group&lt;br /&gt;&lt;br /&gt;child&lt;br /&gt;  text: "This is child "c"."&lt;br /&gt;  id   = "c"&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;For structured XML that uses the &amp;#8220;id&amp;#8221; attribute to identify unique&lt;br /&gt;nodes of interest, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;XMLID()&lt;/span&gt;&lt;/tt&gt; is a convenient way to access the parse&lt;br /&gt;results.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;root&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;    &amp;lt;child id=&amp;quot;a&amp;quot;&amp;gt;This is child &amp;quot;a&amp;quot;.&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;    &amp;lt;child id=&amp;quot;b&amp;quot;&amp;gt;This is child &amp;quot;b&amp;quot;.&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;/group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;    &amp;lt;child id=&amp;quot;c&amp;quot;&amp;gt;This is child &amp;quot;c&amp;quot;.&amp;lt;/child&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;  &amp;lt;/group&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;#39;&amp;#39;&amp;#39;&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&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;&amp;#39;&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;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;XMLID()&lt;/span&gt;&lt;/tt&gt; returns the parsed tree as an Element object,&lt;br /&gt;along with a dictionary mapping the id attribute strings to the&lt;br /&gt;individual nodes in the tree.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python ElementTree_XMLID.py&lt;br /&gt;a = &amp;lt;Element child at d3eb8&amp;gt;&lt;br /&gt;b = &amp;lt;Element child at d3d78&amp;gt;&lt;br /&gt;c = &amp;lt;Element child at d9030&amp;gt;&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;Outline Processor Markup Language, &lt;a class="reference external" href="http://www.opml.org/"&gt;OPML&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Dave Winer&amp;#8217;s OPML specification and documentation.&lt;/dd&gt;&lt;dt&gt;&lt;a class="reference external" href="http://effbot.org/zone/element-xpath.htm"&gt;XPath Support in ElementTree&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Part of Fredrick Lundh&amp;#8217;s original documentation for ElementTree.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;csv&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Read and write comma-separated-value files&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;p&gt;The &lt;a class="reference external" href="http://www.doughellmann.com/PyMOTW/xml/etree/ElementTree/parse.html"&gt;canonical version&lt;/a&gt; of this article&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5440028356946346379-2248271756635298269?l=blog.doughellmann.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=SN85IUHrdek:BDO1skGT8LU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=SN85IUHrdek:BDO1skGT8LU:bcOpcFrp8Mo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=bcOpcFrp8Mo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=SN85IUHrdek:BDO1skGT8LU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?i=SN85IUHrdek:BDO1skGT8LU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PyMOTW/~4/SN85IUHrdek" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.doughellmann.com/feeds/2248271756635298269/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5440028356946346379&amp;postID=2248271756635298269" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/2248271756635298269" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/2248271756635298269" /><link rel="alternate" type="text/html" href="http://feeds.doughellmann.com/~r/PyMOTW/~3/SN85IUHrdek/pymotw-parsing-xml-documents-with.html" title="PyMOTW: Parsing XML Documents with ElementTree" /><author><name>Doug Hellmann</name><uri>http://www.blogger.com/profile/01892352754222143463</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00116818175230541568" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.doughellmann.com/2010/03/pymotw-parsing-xml-documents-with.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-5440028356946346379.post-486143239880400158</id><published>2010-03-07T09:38:00.001-05:00</published><updated>2010-03-07T09:38:33.602-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="PyMOTW" /><title type="text">PyMOTW: tabnanny - Indentation validator</title><content type="html">&lt;div class="section" id="module-tabnanny"&gt;&lt;h1&gt;tabnanny &amp;#8211; Indentation validator&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;Scan Python source code looking for suspicious indentation.&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.1.3 and later&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Consistent use of indentation is important in a langauge like Python,&lt;br /&gt;where white-space is significant.  The tabnanny module provides a&lt;br /&gt;scanner to report on &amp;#8220;ambiguous&amp;#8221; use of indentation.&lt;/p&gt;&lt;div class="section" id="running-from-the-command-line"&gt;&lt;h2&gt;Running from the Command Line&lt;/h2&gt;&lt;p&gt;The simplest way to use tabnanny is to run it from the command line,&lt;br /&gt;passing the names of files to check.  If you pass directory names, the&lt;br /&gt;directories are scanned recursively to find &lt;cite&gt;.py&lt;/cite&gt; files to check.&lt;/p&gt;&lt;p&gt;When I ran tabnanny across the PyMOTW source code, I found one old&lt;br /&gt;module with tabs instead of spaces:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python -m tabnanny .&lt;br /&gt;./PyMOTW/Queue/fetch_podcasts.py 78 "\t\tfor enclosure in entry.get('enclosures', []):\n"&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Sure enough, line 78 of &lt;cite&gt;fetch_podcasts.py&lt;/cite&gt; had two tabs instead of 8&lt;br /&gt;spaces.  I didn&amp;#8217;t see this by looking at it in my editor because I&lt;br /&gt;have my tabstops set to 4 spaces, so visually there was no difference.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;enclosure&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;enclosures&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&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;&amp;#39;Queuing:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enclosure&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;enclosure_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enclosure&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;url&amp;#39;&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;Correcting line 78 and running tabnanny again showed another error on&lt;br /&gt;line 79.  One last problem showed up on line 80.&lt;/p&gt;&lt;p&gt;If you want to scan files, but not see the details about the error,&lt;br /&gt;you can use the &lt;cite&gt;-q&lt;/cite&gt; option to suppress all information except the&lt;br /&gt;filename.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python -m tabnanny -q .&lt;br /&gt;./PyMOTW/Queue/fetch_podcasts.py&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;To see more information about the files being scanned, use the &lt;cite&gt;-v&lt;/cite&gt; option.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python -m tabnanny -v ./PyMOTW/Queue&lt;br /&gt;'./PyMOTW/Queue': listing directory&lt;br /&gt;'./PyMOTW/Queue/__init__.py': Clean bill of health.&lt;br /&gt;'./PyMOTW/Queue/feedparser.py': Clean bill of health.&lt;br /&gt;'./PyMOTW/Queue/fetch_podcasts.py': *** Line 78: trouble in tab city! ***&lt;br /&gt;offending line: "\t\tfor enclosure in entry.get('enclosures', []):\n"&lt;br /&gt;indent not greater e.g. at tab sizes 1, 2&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="using-within-your-program"&gt;&lt;h2&gt;Using within Your Program&lt;/h2&gt;&lt;p&gt;As soon as I discovered the mistake in my Queue example, I decided I&lt;br /&gt;needed to add a tabnanny check to my PyMOTW build process.  I created&lt;br /&gt;a tabcheck task in my pavement.py build script so I could run &lt;cite&gt;paver&lt;br /&gt;tabcheck&lt;/cite&gt; and scan the code I&amp;#8217;m working on for PyMOTW.  This is&lt;br /&gt;possible because tabnanny exposes its &lt;cite&gt;check()&lt;/cite&gt; function as a public&lt;br /&gt;API.&lt;/p&gt;&lt;p&gt;Here&amp;#8217;s an example of using tabnanny that doesn&amp;#8217;t require understanding&lt;br /&gt;Paver&amp;#8217;s task definition decorators.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tabnanny&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="c"&gt;# Turn on verbose mode&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;tabnanny&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dirname&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;tabnanny&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirname&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;And in action:&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python tabnanny_check.py ../Queue&lt;br /&gt;'../Queue': listing directory&lt;br /&gt;'../Queue/__init__.py': Clean bill of health.&lt;br /&gt;'../Queue/feedparser.py': Clean bill of health.&lt;br /&gt;'../Queue/fetch_podcasts.py': *** Line 78: trouble in tab city! ***&lt;br /&gt;offending line: "\t\tfor enclosure in entry.get('enclosures', []):\n"&lt;br /&gt;indent not greater e.g. at tab sizes 1, 2&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;If you run these examples against the PyMOTW code it won&amp;#8217;t report&lt;br /&gt;the same errors, since I have fixed my code in this release.&lt;/p&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/tabnanny.html"&gt;tabnanny&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;tokenize&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Lexical scanner for Python source code.&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;p&gt;The &lt;a class="reference external" href="http://www.doughellmann.com/PyMOTW/tabnanny/"&gt;canonical version&lt;/a&gt; of this article&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5440028356946346379-486143239880400158?l=blog.doughellmann.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=FzgqNrcDZ7c:bVSft9ehPEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=FzgqNrcDZ7c:bVSft9ehPEA:bcOpcFrp8Mo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=bcOpcFrp8Mo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=FzgqNrcDZ7c:bVSft9ehPEA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?i=FzgqNrcDZ7c:bVSft9ehPEA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PyMOTW/~4/FzgqNrcDZ7c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.doughellmann.com/feeds/486143239880400158/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5440028356946346379&amp;postID=486143239880400158" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/486143239880400158" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/486143239880400158" /><link rel="alternate" type="text/html" href="http://feeds.doughellmann.com/~r/PyMOTW/~3/FzgqNrcDZ7c/pymotw-tabnanny-indentation-validator.html" title="PyMOTW: tabnanny - Indentation validator" /><author><name>Doug Hellmann</name><uri>http://www.blogger.com/profile/01892352754222143463</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00116818175230541568" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.doughellmann.com/2010/03/pymotw-tabnanny-indentation-validator.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-5440028356946346379.post-1798430184837221280</id><published>2010-01-30T13:11:00.001-05:00</published><updated>2010-01-30T17:42:08.432-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="PyMOTW" /><title type="text">PyMOTW: cgitb - Detailed traceback reports</title><content type="html">&lt;div class="section" id="module-cgitb"&gt;&lt;h1&gt;cgitb &amp;#8211; Detailed traceback reports&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;cgitb provides more detailed traceback information than &lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;traceback&lt;/span&gt;&lt;/tt&gt;.&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.2 and later&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;cgitb was originally designed for showing errors and debugging&lt;br /&gt;information in web applications.  It was later updated to include&lt;br /&gt;plain-text output as well, but unfortunately wasn&amp;#8217;t renamed.  This has&lt;br /&gt;led to obscurity and the module is not used as often as it should be.&lt;br /&gt;Nonetheless, cgitb is a valuable debugging tool in the standard&lt;br /&gt;library.&lt;/p&gt;&lt;div class="section" id="standard-traceback-dumps"&gt;&lt;br /&gt;&lt;h2&gt;Standard Traceback Dumps&lt;/h2&gt;&lt;p&gt;Python&amp;#8217;s default exception handling behavior is to print a &lt;em&gt;traceback&lt;/em&gt;to standard error with the call stack leading up to the error&lt;br /&gt;position.  This basic output is frequently enough information to&lt;br /&gt;understand the cause of the exception and permit a fix.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local_var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local_var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;local_var&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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 above sample program has a subtle error in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;func3()&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_basic_traceback.py&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_basic_traceback.py", line 22, in &amp;lt;module&amp;gt;&lt;br /&gt;    func1(1)&lt;br /&gt;  File "cgitb_basic_traceback.py", line 12, in func1&lt;br /&gt;    return func2(local_var)&lt;br /&gt;  File "cgitb_basic_traceback.py", line 16, in func2&lt;br /&gt;    return func3(local_var)&lt;br /&gt;  File "cgitb_basic_traceback.py", line 19, in func3&lt;br /&gt;    local_var = arg2 / 2&lt;br /&gt;NameError: global name 'arg2' is not defined&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="enabling-detailed-tracebacks"&gt;&lt;h2&gt;Enabling Detailed Tracebacks&lt;/h2&gt;&lt;p&gt;While the basic traceback includes enough information for us to spot&lt;br /&gt;the error, enabling cgitb replaces &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;sys.excepthook&lt;/span&gt;&lt;/tt&gt; with a function&lt;br /&gt;that gives extended tracebacks with even more detail.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local_var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local_var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;local_var&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;As you can see below, the error report is much more extensive.  Each&lt;br /&gt;frame of the stack is listed, along with:&lt;/p&gt;&lt;ul class="simple"&gt;&lt;li&gt;the full path to the source file, instead of just the base name&lt;/li&gt;&lt;li&gt;the values of the arguments to each function in the stack&lt;/li&gt;&lt;li&gt;a few lines of source context from around the line in the error path&lt;/li&gt;&lt;li&gt;the values of variables in the expression causing the error&lt;/li&gt;&lt;/ul&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_extended_traceback.py&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;type 'exceptions.NameError'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:27 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_extended_traceback.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   21 def func3(arg3):&lt;br /&gt;   22     local_var = arg2 / 2&lt;br /&gt;   23     return local_var&lt;br /&gt;   24&lt;br /&gt;   25 func1(1)&lt;br /&gt;func1 = &amp;lt;function func1 at 0x7bbb0&amp;gt;&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_extended_traceback.py in func1(arg1=1)&lt;br /&gt;   13 def func1(arg1):&lt;br /&gt;   14     local_var = arg1 * 2&lt;br /&gt;   15     return func2(local_var)&lt;br /&gt;   16&lt;br /&gt;   17 def func2(arg2):&lt;br /&gt;global func2 = &amp;lt;function func2 at 0x7bbf0&amp;gt;&lt;br /&gt;local_var = 2&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_extended_traceback.py in func2(arg2=2)&lt;br /&gt;   17 def func2(arg2):&lt;br /&gt;   18     local_var = arg2 + 2&lt;br /&gt;   19     return func3(local_var)&lt;br /&gt;   20&lt;br /&gt;   21 def func3(arg3):&lt;br /&gt;global func3 = &amp;lt;function func3 at 0x7bc30&amp;gt;&lt;br /&gt;local_var = 4&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_extended_traceback.py in func3(arg3=4)&lt;br /&gt;   20&lt;br /&gt;   21 def func3(arg3):&lt;br /&gt;   22     local_var = arg2 / 2&lt;br /&gt;   23     return local_var&lt;br /&gt;   24&lt;br /&gt;local_var undefined&lt;br /&gt;arg2 undefined&lt;br /&gt;&amp;lt;type 'exceptions.NameError'&amp;gt;: global name 'arg2' is not defined&lt;br /&gt;    __class__ = &amp;lt;type 'exceptions.NameError'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __dict__ = {}&lt;br /&gt;    __doc__ = 'Name not found globally.'&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;method-wrapper '__init__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5b0aa0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0x5b0aa0&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of exceptions.NameError object at 0x81710&amp;gt;&lt;br /&gt;    args = ("global name 'arg2' is not defined",)&lt;br /&gt;    message = "global name 'arg2' is not defined"&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_extended_traceback.py", line 25, in &amp;lt;module&amp;gt;&lt;br /&gt;    func1(1)&lt;br /&gt;  File "cgitb_extended_traceback.py", line 15, in func1&lt;br /&gt;    return func2(local_var)&lt;br /&gt;  File "cgitb_extended_traceback.py", line 19, in func2&lt;br /&gt;    return func3(local_var)&lt;br /&gt;  File "cgitb_extended_traceback.py", line 22, in func3&lt;br /&gt;    local_var = arg2 / 2&lt;br /&gt;NameError: global name 'arg2' is not defined&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;The end of the output also includes the full details of the exception&lt;br /&gt;object (in case it has attributes other than &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;message&lt;/span&gt;&lt;/tt&gt; that would be&lt;br /&gt;useful for debugging) and the original form of a traceback dump.&lt;/p&gt;&lt;/div&gt;&lt;div class="section" id="local-variables-in-tracebacks"&gt;&lt;h2&gt;Local Variables in Tracebacks&lt;/h2&gt;&lt;p&gt;Having access to the variables involved in the error stack can help&lt;br /&gt;find a logical error that occurs somewhere higher in the stack than&lt;br /&gt;the line where the actual exception is generated.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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;In the case of this code with a ZeroDivisionError, we can see that the&lt;br /&gt;problem is introduced in the computation of the value of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;c&lt;/span&gt;&lt;/tt&gt; in&lt;br /&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;func1()&lt;/span&gt;&lt;/tt&gt;, rather than where the value is used in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;func2()&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_local_vars.py&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:27 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_local_vars.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   16 def func1(a, b):&lt;br /&gt;   17     c = b - 5&lt;br /&gt;   18     return func2(a, c)&lt;br /&gt;   19&lt;br /&gt;   20 func1(1, 5)&lt;br /&gt;func1 = &amp;lt;function func1 at 0x7bbf0&amp;gt;&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_local_vars.py in func1(a=1, b=5)&lt;br /&gt;   16 def func1(a, b):&lt;br /&gt;   17     c = b - 5&lt;br /&gt;   18     return func2(a, c)&lt;br /&gt;   19&lt;br /&gt;   20 func1(1, 5)&lt;br /&gt;global func2 = &amp;lt;function func2 at 0x7bbb0&amp;gt;&lt;br /&gt;a = 1&lt;br /&gt;c = 0&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_local_vars.py in func2(a=1, divisor=0)&lt;br /&gt;   12&lt;br /&gt;   13 def func2(a, divisor):&lt;br /&gt;   14     return a / divisor&lt;br /&gt;   15&lt;br /&gt;   16 def func1(a, b):&lt;br /&gt;a = 1&lt;br /&gt;divisor = 0&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;: integer division or modulo by zero&lt;br /&gt;    __class__ = &amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __dict__ = {}&lt;br /&gt;    __doc__ = 'Second argument to a division or modulo operation was zero.'&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;method-wrapper '__init__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of exceptions.ZeroDivisionError object at 0x825a8&amp;gt;&lt;br /&gt;    args = ('integer division or modulo by zero',)&lt;br /&gt;    message = 'integer division or modulo by zero'&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_local_vars.py", line 20, in &amp;lt;module&amp;gt;&lt;br /&gt;    func1(1, 5)&lt;br /&gt;  File "cgitb_local_vars.py", line 18, in func1&lt;br /&gt;    return func2(a, c)&lt;br /&gt;  File "cgitb_local_vars.py", line 14, in func2&lt;br /&gt;    return a / divisor&lt;br /&gt;ZeroDivisionError: integer division or modulo by zero&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;The code in cgitb that examines the variables used in the stack frame&lt;br /&gt;leading to the error is smart enough to evaluate object attributes to&lt;br /&gt;display them, too.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrokenClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;This class has an error.&lt;/span&gt;&lt;br /&gt;&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Be careful passing arguments in here.&lt;/span&gt;&lt;br /&gt;&lt;span class="sd"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BrokenClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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;Here we see that &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;self.a&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;self.b&lt;/span&gt;&lt;/tt&gt; are involved in the&lt;br /&gt;error-prone code.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_with_classes.py&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:27 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_with_classes.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   24         return&lt;br /&gt;   25&lt;br /&gt;   26 o = BrokenClass(1, 0)&lt;br /&gt;   27&lt;br /&gt;   28&lt;br /&gt;o undefined&lt;br /&gt;BrokenClass = &amp;lt;class '__main__.BrokenClass'&amp;gt;&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_with_classes.py in __init__(self=&amp;lt;__main__.BrokenClass object at 0x81e30&amp;gt;, a=1, b=0)&lt;br /&gt;   21         self.b = b&lt;br /&gt;   22         self.c = self.a * self.b&lt;br /&gt;   23         self.d = self.a / self.b&lt;br /&gt;   24         return&lt;br /&gt;   25&lt;br /&gt;self = &amp;lt;__main__.BrokenClass object at 0x81e30&amp;gt;&lt;br /&gt;self.d undefined&lt;br /&gt;self.a = 1&lt;br /&gt;self.b = 0&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;: integer division or modulo by zero&lt;br /&gt;    __class__ = &amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __dict__ = {}&lt;br /&gt;    __doc__ = 'Second argument to a division or modulo operation was zero.'&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;method-wrapper '__init__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of exceptions.ZeroDivisionError object at 0x7f710&amp;gt;&lt;br /&gt;    args = ('integer division or modulo by zero',)&lt;br /&gt;    message = 'integer division or modulo by zero'&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_with_classes.py", line 26, in &amp;lt;module&amp;gt;&lt;br /&gt;    o = BrokenClass(1, 0)&lt;br /&gt;  File "cgitb_with_classes.py", line 23, in __init__&lt;br /&gt;    self.d = self.a / self.b&lt;br /&gt;ZeroDivisionError: integer division or modulo by zero&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="adding-more-context"&gt;&lt;h2&gt;Adding More Context&lt;/h2&gt;&lt;p&gt;Suppose your function includes a lot of inline comments, whitespace,&lt;br /&gt;or other code that makes it very long.  Having the default of 5 lines&lt;br /&gt;of context may not be enough help in that case, if the body of the&lt;br /&gt;function is pushed out of the code window displayed.  Using a larger&lt;br /&gt;context value when enabling cgitb gets around this.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&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;context_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# Really&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# long&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# comment&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# goes&lt;/span&gt;&lt;br /&gt;    &lt;span class="c"&gt;# here.&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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;You can pass &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;context&lt;/span&gt;&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cgitb.enable()&lt;/span&gt;&lt;/tt&gt; to control the amount&lt;br /&gt;of code displayed for each line of the traceback.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_more_context.py 5&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:27 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_more_context.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   24     # goes&lt;br /&gt;   25     # here.&lt;br /&gt;   26     return func2(a, c)&lt;br /&gt;   27&lt;br /&gt;   28 func1(1, 5)&lt;br /&gt;func1 = &amp;lt;function func1 at 0x7bbb0&amp;gt;&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_more_context.py in func1(a=1, b=5)&lt;br /&gt;   24     # goes&lt;br /&gt;   25     # here.&lt;br /&gt;   26     return func2(a, c)&lt;br /&gt;   27&lt;br /&gt;   28 func1(1, 5)&lt;br /&gt;global func2 = &amp;lt;function func2 at 0x7bb70&amp;gt;&lt;br /&gt;a = 1&lt;br /&gt;c = 0&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_more_context.py in func2(a=1, divisor=0)&lt;br /&gt;   15&lt;br /&gt;   16 def func2(a, divisor):&lt;br /&gt;   17     return a / divisor&lt;br /&gt;   18&lt;br /&gt;   19 def func1(a, b):&lt;br /&gt;a = 1&lt;br /&gt;divisor = 0&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;: integer division or modulo by zero&lt;br /&gt;    __class__ = &amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __dict__ = {}&lt;br /&gt;    __doc__ = 'Second argument to a division or modulo operation was zero.'&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;method-wrapper '__init__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    args = ('integer division or modulo by zero',)&lt;br /&gt;    message = 'integer division or modulo by zero'&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_more_context.py", line 28, in &amp;lt;module&amp;gt;&lt;br /&gt;    func1(1, 5)&lt;br /&gt;  File "cgitb_more_context.py", line 26, in func1&lt;br /&gt;    return func2(a, c)&lt;br /&gt;  File "cgitb_more_context.py", line 17, in func2&lt;br /&gt;    return a / divisor&lt;br /&gt;ZeroDivisionError: integer division or modulo by zero&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Increasing the value gets us enough of the function that we can spot&lt;br /&gt;the problem in the code, again.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_more_context.py 10&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:28 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_more_context.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   19 def func1(a, b):&lt;br /&gt;   20     c = b - 5&lt;br /&gt;   21     # Really&lt;br /&gt;   22     # long&lt;br /&gt;   23     # comment&lt;br /&gt;   24     # goes&lt;br /&gt;   25     # here.&lt;br /&gt;   26     return func2(a, c)&lt;br /&gt;   27&lt;br /&gt;   28 func1(1, 5)&lt;br /&gt;func1 = &amp;lt;function func1 at 0x7bbb0&amp;gt;&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_more_context.py in func1(a=1, b=5)&lt;br /&gt;   19 def func1(a, b):&lt;br /&gt;   20     c = b - 5&lt;br /&gt;   21     # Really&lt;br /&gt;   22     # long&lt;br /&gt;   23     # comment&lt;br /&gt;   24     # goes&lt;br /&gt;   25     # here.&lt;br /&gt;   26     return func2(a, c)&lt;br /&gt;   27&lt;br /&gt;   28 func1(1, 5)&lt;br /&gt;global func2 = &amp;lt;function func2 at 0x7bb70&amp;gt;&lt;br /&gt;a = 1&lt;br /&gt;c = 0&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_more_context.py in func2(a=1, divisor=0)&lt;br /&gt;   12&lt;br /&gt;   13 context_length = int(sys.argv[1])&lt;br /&gt;   14 cgitb.enable(format='text', context=context_length)&lt;br /&gt;   15&lt;br /&gt;   16 def func2(a, divisor):&lt;br /&gt;   17     return a / divisor&lt;br /&gt;   18&lt;br /&gt;   19 def func1(a, b):&lt;br /&gt;   20     c = b - 5&lt;br /&gt;   21     # Really&lt;br /&gt;a = 1&lt;br /&gt;divisor = 0&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;: integer division or modulo by zero&lt;br /&gt;    __class__ = &amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __dict__ = {}&lt;br /&gt;    __doc__ = 'Second argument to a division or modulo operation was zero.'&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;method-wrapper '__init__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of exceptions.ZeroDivisionError object at 0x816c0&amp;gt;&lt;br /&gt;    args = ('integer division or modulo by zero',)&lt;br /&gt;    message = 'integer division or modulo by zero'&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_more_context.py", line 28, in &amp;lt;module&amp;gt;&lt;br /&gt;    func1(1, 5)&lt;br /&gt;  File "cgitb_more_context.py", line 26, in func1&lt;br /&gt;    return func2(a, c)&lt;br /&gt;  File "cgitb_more_context.py", line 17, in func2&lt;br /&gt;    return a / divisor&lt;br /&gt;ZeroDivisionError: integer division or modulo by zero&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="exception-properties"&gt;&lt;h2&gt;Exception Properties&lt;/h2&gt;&lt;p&gt;In addition to the local variables from each stack frame, cgitb shows&lt;br /&gt;all properties of the exception object.  If you have a custom&lt;br /&gt;exception type with extra properties, they are printed as part of the&lt;br /&gt;error report.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Add extra properties to a special exception&lt;/span&gt;&lt;br /&gt;&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bad_value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bad_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bad_value&lt;/span&gt;&lt;br /&gt;        &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;MyException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Normal message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bad_value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;99&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;In this example, the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;bad_value&lt;/span&gt;&lt;/tt&gt; property is included along with the&lt;br /&gt;standard &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;message&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;args&lt;/span&gt;&lt;/tt&gt; values.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_exception_properties.py&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;class '__main__.MyException'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:28 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_exception_properties.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   18         self.bad_value = bad_value&lt;br /&gt;   19         Exception.__init__(self, message)&lt;br /&gt;   20         return&lt;br /&gt;   21&lt;br /&gt;   22 raise MyException('Normal message', bad_value=99)&lt;br /&gt;MyException = &amp;lt;class '__main__.MyException'&amp;gt;&lt;br /&gt;bad_value undefined&lt;br /&gt;&amp;lt;class '__main__.MyException'&amp;gt;: Normal message&lt;br /&gt;    __class__ = &amp;lt;class '__main__.MyException'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __dict__ = {'bad_value': 99}&lt;br /&gt;    __doc__ = 'Add extra properties to a special exception\n    '&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;bound method MyException.__init__ of MyException('Normal message',)&amp;gt;&lt;br /&gt;    __module__ = '__main__'&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5aebc0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0xa16890&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of MyException object at 0x7f698&amp;gt;&lt;br /&gt;    __weakref__ = None&lt;br /&gt;    args = ('Normal message',)&lt;br /&gt;    bad_value = 99&lt;br /&gt;    message = 'Normal message'&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_exception_properties.py", line 22, in &amp;lt;module&amp;gt;&lt;br /&gt;    raise MyException('Normal message', bad_value=99)&lt;br /&gt;MyException: Normal message&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="logging-tracebacks"&gt;&lt;h2&gt;Logging Tracebacks&lt;/h2&gt;&lt;p&gt;For many situations, printing the traceback details to standard error&lt;br /&gt;is the best resolution.  In a production system, however, logging the&lt;br /&gt;errors is even better.  &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cgitb.enable()&lt;/span&gt;&lt;/tt&gt; includes an optional&lt;br /&gt;argument, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;logdir&lt;/span&gt;&lt;/tt&gt;, to enable error logging.  When a directory name&lt;br /&gt;is provided, each exception is logged to its own file in the given&lt;br /&gt;directory.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&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;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logdir&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;path&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;LOGS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br /&gt;             &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;             &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&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;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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;Event with the error display suppressed, a message is printed&lt;br /&gt;describing where to go to find the error log.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python cgitb_log_exception.py&lt;br /&gt;/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/cgitb.py:245: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6&lt;br /&gt;  value = pydoc.text.repr(getattr(evalue, name))&lt;br /&gt;&amp;lt;p&amp;gt;A problem occurred in a Python script.&lt;br /&gt;&amp;lt;p&amp;gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/LOGS/tmpohlTP8.txt contains the description of this error.&lt;br /&gt;&lt;br /&gt;$ ls LOGS&lt;br /&gt;tmpohlTP8.txt&lt;br /&gt;&lt;br /&gt;$ cat LOGS/*.txt&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;Python 2.6.2: /Users/dhellmann/.virtualenvs/pymotw/bin/python&lt;br /&gt;Sat Jan 30 12:50:28 2010&lt;br /&gt;&lt;br /&gt;A problem occurred in a Python script.  Here is the sequence of&lt;br /&gt;function calls leading up to the error, in the order they occurred.&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_log_exception.py in &amp;lt;module&amp;gt;()&lt;br /&gt;   21 def func1(a, b):&lt;br /&gt;   22     c = b - 5&lt;br /&gt;   23     return func2(a, c)&lt;br /&gt;   24&lt;br /&gt;   25 func1(1, 5)&lt;br /&gt;func1 = &amp;lt;function func1 at 0x7bbb0&amp;gt;&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_log_exception.py in func1(a=1, b=5)&lt;br /&gt;   21 def func1(a, b):&lt;br /&gt;   22     c = b - 5&lt;br /&gt;   23     return func2(a, c)&lt;br /&gt;   24&lt;br /&gt;   25 func1(1, 5)&lt;br /&gt;global func2 = &amp;lt;function func2 at 0x7bb70&amp;gt;&lt;br /&gt;a = 1&lt;br /&gt;c = 0&lt;br /&gt;&lt;br /&gt; /Users/dhellmann/Documents/PyMOTW/src/PyMOTW/cgitb/cgitb_log_exception.py in func2(a=1, divisor=0)&lt;br /&gt;   17&lt;br /&gt;   18 def func2(a, divisor):&lt;br /&gt;   19     return a / divisor&lt;br /&gt;   20&lt;br /&gt;   21 def func1(a, b):&lt;br /&gt;a = 1&lt;br /&gt;divisor = 0&lt;br /&gt;&amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;: integer division or modulo by zero&lt;br /&gt;    __class__ = &amp;lt;type 'exceptions.ZeroDivisionError'&amp;gt;&lt;br /&gt;    __delattr__ = &amp;lt;method-wrapper '__delattr__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __dict__ = {}&lt;br /&gt;    __doc__ = 'Second argument to a division or modulo operation was zero.'&lt;br /&gt;    __format__ = &amp;lt;built-in method __format__ of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __getattribute__ = &amp;lt;method-wrapper '__getattribute__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __getitem__ = &amp;lt;method-wrapper '__getitem__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __getslice__ = &amp;lt;method-wrapper '__getslice__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __hash__ = &amp;lt;method-wrapper '__hash__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __init__ = &amp;lt;method-wrapper '__init__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __new__ = &amp;lt;built-in method __new__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __reduce__ = &amp;lt;built-in method __reduce__ of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __reduce_ex__ = &amp;lt;built-in method __reduce_ex__ of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __repr__ = &amp;lt;method-wrapper '__repr__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __setattr__ = &amp;lt;method-wrapper '__setattr__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __setstate__ = &amp;lt;built-in method __setstate__ of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __sizeof__ = &amp;lt;built-in method __sizeof__ of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __str__ = &amp;lt;method-wrapper '__str__' of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    __subclasshook__ = &amp;lt;built-in method __subclasshook__ of type object at 0x5af9c0&amp;gt;&lt;br /&gt;    __unicode__ = &amp;lt;built-in method __unicode__ of exceptions.ZeroDivisionError object at 0x81710&amp;gt;&lt;br /&gt;    args = ('integer division or modulo by zero',)&lt;br /&gt;    message = 'integer division or modulo by zero'&lt;br /&gt;&lt;br /&gt;The above is a description of an error in a Python program.  Here is&lt;br /&gt;the original traceback:&lt;br /&gt;&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "cgitb_log_exception.py", line 25, in &amp;lt;module&amp;gt;&lt;br /&gt;    func1(1, 5)&lt;br /&gt;  File "cgitb_log_exception.py", line 23, in func1&lt;br /&gt;    return func2(a, c)&lt;br /&gt;  File "cgitb_log_exception.py", line 19, in func2&lt;br /&gt;    return a / divisor&lt;br /&gt;ZeroDivisionError: integer division or modulo by zero&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="html-output"&gt;&lt;h2&gt;HTML Output&lt;/h2&gt;&lt;p&gt;Of course, since cgitb was originally developed for handling&lt;br /&gt;exceptions in web apps, no discussion would be complete without an&lt;br /&gt;example of the HTML output it produces.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cgitb&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;cgitb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local_var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local_var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;func3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;local_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;local_var&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;func1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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 leaving out the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;format&lt;/span&gt;&lt;/tt&gt; argument (or specifying &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;html&lt;/span&gt;&lt;/tt&gt;), the&lt;br /&gt;traceback format changes to HTML output.&lt;/p&gt;&lt;img alt="HTML output example" src="http://www.doughellmann.com/PyMOTW/_images/html_error.png" /&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/cgitb.html"&gt;cgitb&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;traceback&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;Standard library module for working with tracebacks.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;inspect&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;The inspect module includes more functions for examining the&lt;br /&gt;stack.&lt;/dd&gt;&lt;dt&gt;&lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;sys&lt;/span&gt;&lt;/tt&gt;&lt;/dt&gt;&lt;dd&gt;The sys module provides access to the current exception value&lt;br /&gt;and the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;excepthook&lt;/span&gt;&lt;/tt&gt; handler invoked when an exception&lt;br /&gt;occurs.&lt;/dd&gt;&lt;dt&gt;&lt;a class="reference external" href="http://thread.gmane.org/gmane.comp.python.devel/110326"&gt;Improved traceback module&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Python-dev discussion of improvements to the traceback module&lt;br /&gt;and related enhancements other developers use locally.&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;p&gt;The &lt;a class="reference external" href="http://www.doughellmann.com/PyMOTW/cgitb/"&gt;canonical version&lt;/a&gt; of this article&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5440028356946346379-1798430184837221280?l=blog.doughellmann.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=GW_WXSq4Vy0:9rvv0JARPMk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=GW_WXSq4Vy0:9rvv0JARPMk:bcOpcFrp8Mo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=bcOpcFrp8Mo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=GW_WXSq4Vy0:9rvv0JARPMk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?i=GW_WXSq4Vy0:9rvv0JARPMk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PyMOTW/~4/GW_WXSq4Vy0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.doughellmann.com/feeds/1798430184837221280/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5440028356946346379&amp;postID=1798430184837221280" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/1798430184837221280" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/1798430184837221280" /><link rel="alternate" type="text/html" href="http://feeds.doughellmann.com/~r/PyMOTW/~3/GW_WXSq4Vy0/pymotw-cgitb-detailed-traceback-reports.html" title="PyMOTW: cgitb - Detailed traceback reports" /><author><name>Doug Hellmann</name><uri>http://www.blogger.com/profile/01892352754222143463</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00116818175230541568" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.doughellmann.com/2010/01/pymotw-cgitb-detailed-traceback-reports.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-5440028356946346379.post-3087884088937397190</id><published>2009-11-29T12:16:00.001-05:00</published><updated>2009-11-29T12:16:44.646-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="PyMOTW" /><title type="text">PyMOTW: plistlib - Manipulate OS X property list files</title><content type="html">&lt;div class="section" id="module-plistlib"&gt;&lt;h1&gt;plistlib &amp;#8211; Manipulate OS X property list files&lt;/h1&gt;&lt;table class="docutils field-list" frame="void" rules="none"&gt;&lt;col class="field-name"&gt;&lt;/col&gt;&lt;col class="field-body"&gt;&lt;/col&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 and write OS X property list files&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.6&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;plistlib provides an interface for working with property list files&lt;br /&gt;used under OS X.  plist files are typically XML, sometimes compressed.&lt;br /&gt;They are used by the operating system and applications to store&lt;br /&gt;preferences or other configuration settings.  The contents are usually&lt;br /&gt;structured as a dictionary containing key value pairs of basic&lt;br /&gt;built-in types (unicode strings, integers, dates, etc.).  Values can&lt;br /&gt;also be nested data structures such as other dictionaries or lists.&lt;br /&gt;Binary data, or strings with control characters, can be encoded using&lt;br /&gt;the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;data&lt;/span&gt;&lt;/tt&gt; type.&lt;/p&gt;&lt;div class="section" id="reading-plist-files"&gt;&lt;h2&gt;Reading plist Files&lt;/h2&gt;&lt;p&gt;OS X applications such as iCal use plist files to store meta-data&lt;br /&gt;about objects they manage.  For example, iCal stores the definitions&lt;br /&gt;of all of your calendars as a series of plist files in the Library&lt;br /&gt;directory.&lt;/p&gt;&lt;div class="highlight-xml"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;quot;-//Apple//DTD PLIST 1.0//EN&amp;quot; &amp;quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;AlarmFilter&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;AlarmsDisabled&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;false/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;AttachmentFilter&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;AutoRefresh&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Checked&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;integer&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/integer&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Color&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;#808000FF&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Enabled&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Key&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;4221BCE5-1017-4EE4-B7FF-311A846C600D&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;NeedsForcedUpdate&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;false/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;NeedsRefresh&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Order&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;integer&amp;gt;&lt;/span&gt;25&lt;span class="nt"&gt;&amp;lt;/integer&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RefreshDate&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;date&amp;gt;&lt;/span&gt;2009-11-29T16:31:53Z&lt;span class="nt"&gt;&amp;lt;/date&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RefreshInterval&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;integer&amp;gt;&lt;/span&gt;3600&lt;span class="nt"&gt;&amp;lt;/integer&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;SubscriptionTitle&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Athens, GA Weather - By Weather Underground&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;SubscriptionURL&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;http://ical.wunderground.com/auto/ical/GA/Athens.ics?units=both&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;TaskFilter&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Athens, GA Weather - By Weather Underground&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Type&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;	&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Subscription&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This sample script finds the calendar defintions, reads&lt;br /&gt;them, and prints the titles of any calendars being displayed by iCal&lt;br /&gt;(having the property &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Checked&lt;/span&gt;&lt;/tt&gt; set to a true value).&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;plistlib&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;glob&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;calendar_root&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;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expanduser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;~/Library/Calendars&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="n"&gt;calendar_directories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&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;path&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;calendar_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;*.caldav&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;*.calendar&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&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;path&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;calendar_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;*.calendar&amp;#39;&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;br /&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dirname&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;calendar_directories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;info_filename&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;path&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;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Info.plist&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="k"&gt;if&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;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info_filename&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;plistlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readPlist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="k"&gt;if&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Checked&amp;#39;&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;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Title&amp;#39;&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 type of the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Checked&lt;/span&gt;&lt;/tt&gt; property is defined by the plist file, so&lt;br /&gt;our script does not need to convert the string to an integer.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python plistlib_checked_calendars.py&lt;br /&gt;Doug Hellmann&lt;br /&gt;Tasks&lt;br /&gt;Vacation Schedule&lt;br /&gt;EarthSeasons&lt;br /&gt;US Holidays&lt;br /&gt;Athens, GA Weather - By Weather Underground&lt;br /&gt;Birthdays&lt;br /&gt;Georgia Bulldogs Calendar (NCAA Football)&lt;br /&gt;Home&lt;br /&gt;Meetup: Django&lt;br /&gt;Meetup: Python&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="writing-plist-files"&gt;&lt;h2&gt;Writing plist Files&lt;/h2&gt;&lt;p&gt;If you want to use plist files to save your own settings, use&lt;br /&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;writePlist()&lt;/span&gt;&lt;/tt&gt; to serialize the data and write it to the filesystem.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;plistlib&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tempfile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;an_int&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;a_bool&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;the_float&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;5.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;simple_string&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;This string has no special characters.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;xml_string&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&amp;lt;element attr=&amp;quot;value&amp;quot;&amp;gt;This string includes XML markup &amp;amp;nbsp;&amp;lt;/element&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;nested_list&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;nested_dict&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;value&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;&lt;br /&gt;      &lt;span class="s"&gt;&amp;#39;timestamp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&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;br /&gt;&lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NamedTemporaryFile&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;plistlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writePlist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0&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;output_file&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;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class="n"&gt;output_file&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;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The first argument is the data structure to write out, and the second&lt;br /&gt;is an open file handle or the name of a file.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python plistlib_write_plist.py&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&lt;br /&gt;&amp;lt;plist version="1.0"&amp;gt;&lt;br /&gt;&amp;lt;dict&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;a_bool&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;false/&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;an_int&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;integer&amp;gt;2&amp;lt;/integer&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;nested_dict&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;dict&amp;gt;&lt;br /&gt;                &amp;lt;key&amp;gt;key&amp;lt;/key&amp;gt;&lt;br /&gt;                &amp;lt;string&amp;gt;value&amp;lt;/string&amp;gt;&lt;br /&gt;        &amp;lt;/dict&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;nested_list&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;array&amp;gt;&lt;br /&gt;                &amp;lt;string&amp;gt;a&amp;lt;/string&amp;gt;&lt;br /&gt;                &amp;lt;string&amp;gt;b&amp;lt;/string&amp;gt;&lt;br /&gt;                &amp;lt;string&amp;gt;c&amp;lt;/string&amp;gt;&lt;br /&gt;        &amp;lt;/array&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;simple_string&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;string&amp;gt;This string has no special characters.&amp;lt;/string&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;the_float&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;real&amp;gt;5.9000000000000004&amp;lt;/real&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;timestamp&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;date&amp;gt;2009-11-29T12:09:35Z&amp;lt;/date&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;xml_string&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;string&amp;gt;&amp;amp;lt;element attr="value"&amp;amp;gt;This string includes XML markup &amp;amp;amp;nbsp;&amp;amp;lt;/element&amp;amp;gt;&amp;lt;/string&amp;gt;&lt;br /&gt;&amp;lt;/dict&amp;gt;&lt;br /&gt;&amp;lt;/plist&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="section" id="binary-property-data"&gt;&lt;br /&gt;&lt;h2&gt;Binary Property Data&lt;/h2&gt;&lt;p&gt;Serializing binary data or strings that may include control characters&lt;br /&gt;using a plist is not immune to the typical challenges for an XML&lt;br /&gt;format.  To work around the issues, plist files can store binary data&lt;br /&gt;in &lt;tt class="xref docutils literal"&gt;&lt;span class="pre"&gt;base64&lt;/span&gt;&lt;/tt&gt; format if the object is wrapped with a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Data&lt;/span&gt;&lt;/tt&gt;instance.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;plistlib&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;binary_data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;plistlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;This data has an embedded null. &lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&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;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;plistlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writePlistToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&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;This example uses the ToString version of the write function to create&lt;br /&gt;an in-memory string instead of writing to a file.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python plistlib_binary_write.py&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&lt;br /&gt;&amp;lt;plist version="1.0"&amp;gt;&lt;br /&gt;&amp;lt;dict&amp;gt;&lt;br /&gt;        &amp;lt;key&amp;gt;binary_data&amp;lt;/key&amp;gt;&lt;br /&gt;        &amp;lt;data&amp;gt;&lt;br /&gt;        VGhpcyBkYXRhIGhhcyBhbiBlbWJlZGRlZCBudWxsLiAA&lt;br /&gt;        &amp;lt;/data&amp;gt;&lt;br /&gt;&amp;lt;/dict&amp;gt;&lt;br /&gt;&amp;lt;/plist&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Binary data is automatically converted to a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Data&lt;/span&gt;&lt;/tt&gt; instance when&lt;br /&gt;read.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;plistlib&lt;/span&gt;&lt;br /&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pprint&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;&amp;quot;&amp;quot;&amp;quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;quot;-//Apple Computer//DTD PLIST 1.0//EN&amp;quot; &amp;quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;plist version=&amp;quot;1.0&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;        &amp;lt;key&amp;gt;binary_data&amp;lt;/key&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;        &amp;lt;data&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;        VGhpcyBkYXRhIGhhcyBhbiBlbWJlZGRlZCBudWxsLiAA&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;        &amp;lt;/data&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plistlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readPlistFromString&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;br /&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;binary_data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&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;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;data&lt;/span&gt;&lt;/tt&gt; attribute of the object contains the decoded data.&lt;/p&gt;&lt;div class="highlight-python"&gt;&lt;pre&gt;$ python plistlib_binary_read.py&lt;br /&gt;'This data has an embedded null. \x00'&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/plistlib.html"&gt;plistlib&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://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html"&gt;plist manual page&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Documentation of the plist file format.&lt;/dd&gt;&lt;dt&gt;&lt;a class="reference external" href="http://www.wunderground.com/"&gt;Weather Underground&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Free weather information, including ICS and RSS feeds.&lt;/dd&gt;&lt;dt&gt;&lt;a class="reference external" href="http://www.macosxhints.com/article.php?story=20050430105126392"&gt;Convert plist between XML and Binary formats&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;Some plist files are stored in a binary format instead of XML&lt;br /&gt;because the binary format is faster to parse using Apple&amp;#8217;s&lt;br /&gt;libraries.  Python&amp;#8217;s plistlib module does not handle the&lt;br /&gt;binary format, so you may need to convert binary files to XML&lt;br /&gt;using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;plutil&lt;/span&gt;&lt;/tt&gt; before reading them.&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;p&gt;The &lt;a class="reference external" href="http://www.doughellmann.com/PyMOTW/plistlib/"&gt;canonical version&lt;/a&gt; of this article&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5440028356946346379-3087884088937397190?l=blog.doughellmann.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=Lr34aakzoPY:haAPesW9Cs0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=Lr34aakzoPY:haAPesW9Cs0:bcOpcFrp8Mo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?d=bcOpcFrp8Mo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.doughellmann.com/~ff/PyMOTW?a=Lr34aakzoPY:haAPesW9Cs0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/PyMOTW?i=Lr34aakzoPY:haAPesW9Cs0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PyMOTW/~4/Lr34aakzoPY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.doughellmann.com/feeds/3087884088937397190/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=5440028356946346379&amp;postID=3087884088937397190" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/3087884088937397190" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5440028356946346379/posts/default/3087884088937397190" /><link rel="alternate" type="text/html" href="http://feeds.doughellmann.com/~r/PyMOTW/~3/Lr34aakzoPY/pymotw-plistlib-manipulate-os-x.html" title="PyMOTW: plistlib - Manipulate OS X property list files" /><author><name>Doug Hellmann</name><uri>http://www.blogger.com/profile/01892352754222143463</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00116818175230541568" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.doughellmann.com/2009/11/pymotw-plistlib-manipulate-os-x.html</feedburner:origLink></entry></feed>
