<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0cGQHw4eip7ImA9WhBaFE0.&quot;"><id>tag:blogger.com,1999:blog-20144447</id><updated>2013-05-24T07:17:01.232-07:00</updated><category term="UNIX" /><category term="podcast" /><category term="packaging" /><category term="one laptop per child" /><category term="ironpython" /><category term="sprinting" /><category term="import" /><category term="web development" /><category term="protocols" /><category term="conference" /><category term="open source" /><category term="advocacy" /><category term="presentation" /><category term="python 3.0" /><category term="OS X" /><category term="software development" /><category term="GUI" /><category term="Scala" /><category term="python 2.5" /><category term="GSoC" /><category term="Python 2.6" /><category term="lazyweb" /><category term="git" /><category term="python" /><category term="PyCon" /><category term="social graph" /><category term="llvm" /><category term="PhD" /><category term="IDEs" /><category term="realStorage" /><category term="stdlib" /><category term="unicode" /><category term="eclipse" /><category term="vim" /><category term="programming languages" /><category term="app engine" /><category term="python bugs" /><category term="HTML5" /><category term="xml" /><category term="computer science" /><category term="idea" /><category term="oplop" /><category term="python programming" /><category term="java" /><category term="security" /><category term="cell phone" /><category term="programming" /><category term="build system" /><category term="PEPs" /><category term="python-dev" /><category term="textmate" /><category term="aspectj" /><category term="jvm" /><category term="django" /><category term="GHOP" /><category term="PEP 362" /><category term="google chrome" /><category term="question" /><category term="python 2.7" /><category term="importers" /><category term="jquery" /><category term="interview" /><category term="Py3K" /><category term="python language" /><category term="importlib" /><category term="mac" /><category term="HTML" /><category term="parallelism" /><category term="unit testing" /><category term="ocaml" /><category term="wishful thinking" /><category term="thesis idea" /><category term="version control" /><category term="testing" /><category term="JavaScript" /><category term="jython" /><category term="svn" /><category term="pep 3108" /><category term="google" /><category term="package management" /><title>Coder Who Says Py</title><subtitle type="html">A place for me to babble on about Python development, Python itself, and coding in general.  The title is inspired by some knights who enjoy a good shrubbery.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://sayspy.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://sayspy.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>487</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/CoderWhoSaysPy" /><feedburner:info uri="coderwhosayspy" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DUYASX49eSp7ImA9WhBVEkQ.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-7046655929455734223</id><published>2013-04-18T07:59:00.001-07:00</published><updated>2013-04-18T07:59:08.061-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-18T07:59:08.061-07:00</app:edited><title>A decade of commits</title><content type="html">Today marks a decade since I made my first commit to CPython's repository on&amp;nbsp;&lt;span style="background-color: white; font-family: sans-serif; font-size: 14px; white-space: nowrap;"&gt;Sat, 19 Apr 2003 04:00:56 +0000&amp;nbsp;&lt;/span&gt;(&lt;a href="http://mail.python.org/pipermail/python-checkins/2003-April/035332.html"&gt;python-checkins&lt;/a&gt;, &lt;a href="http://hg.python.org/cpython/rev/70d6f8b0fc69"&gt;hg.python.org&lt;/a&gt;). According to Ohloh, I currently sit as the 16th most prolific &lt;a href="https://www.ohloh.net/p/python/contributors?query=&amp;amp;sort=commits"&gt;committers based on commit count&lt;/a&gt;&amp;nbsp;which I can hardly believe. Boy have times changed over the past decade!&lt;br /&gt;
&lt;br /&gt;
Back in April 2003, we were still on CVS on &lt;a href="http://sourceforge.net/projects/python/"&gt;SourceForge&lt;/a&gt;&amp;nbsp;(I somewhat foolishly took on projects to change both of those). &lt;a href="http://mail.python.org/pipermail/python-dev/2003-April/034573.html"&gt;Guido gave me my commit privileges&lt;/a&gt; himself (now I hand them out which is a bit scary =). It was less than a month after the &lt;a href="http://www.linuxjournal.com/article/6800"&gt;first PyCon&lt;/a&gt; (or at least the first Python conference officially called PyCon, and I've managed to attend every single since and now have my wife &lt;b&gt;asking&lt;/b&gt;&amp;nbsp;if she can come) and me being elected to the &lt;a href="http://www.python.org/psf/"&gt;Python Software Foundation&lt;/a&gt;&amp;nbsp;(which I joined the board of directors for a time). This was before Python 2.3 we released (and now we are working on Python 3.4). Back then, Python was becoming popular and had an upward trend, heading towards its current position as the top dynamic language out there that isn't embedded in a browser (I would say it didn't really become really obvious this was going to happen until about 2005, so I got my wagon hitched at just the right time =).&lt;br /&gt;
&lt;br /&gt;
But this post is not about reminiscing. It's for thanking the people and community who have made contributing to Python so enjoyable that I have actually wanted to do it for a whole decade (and will continue to do so for the foreseeable future).&lt;br /&gt;
&lt;br /&gt;
I want to first thank python-dev. I have always said I truly learned how to program from my fellow core developers. Getting to work on CPython's interpreter core and the stdlib showed me how to manage complexity in APIs, keep my code clean and readable, when to optimize and when to go with the easier to read solution, etc. Pretty much everything that you would want to know when programming in the wild I didn't learn from a class or a book but from my fellow open source programmers. You just can't buy that experience. This is the reason I have always done what I could to make the lives of people who wanted to contribute as easy as possible (sometimes at the expense of other core devs depending on how you fall down on the svn -&amp;gt; hg transition).&lt;br /&gt;
&lt;br /&gt;
I also want to thank the Python community. When I first started contributing I was doing it to gain experience in programming in the real world by contributing to a top-notch codebase with world-class programmers. But as time went on the things I gained in terms of experience dwindled. But what I lost in terms of fulfillment from what I learned was more than made up for in terms of the interactions I had with the community. Meeting people who have benefited from my code and said "thanks" for volunteering my time truly does inspire me to keep contributing, especially when I don't want to backport a bug fix. =)&lt;br /&gt;
&lt;br /&gt;
But through the community I have also been able to gain great friends from across the globe. While I may only get to see my "open source friends" about once a year for a week at PyCon (which is the key reason I look forward to the conference as soon as the last one finished), they are truly friends. They are people I would let crash in my spare bedroom, give them a key, and say "welcome" without hesitation (if any of them were ever so inclined to visit Toronto, let alone Guelph). Those friendships are truly important to me and what will keep me coming back for years on in the future no matter how much or little I am able to contribute in my spare time.&lt;br /&gt;
&lt;br /&gt;
So thanks to everyone reading this. By being a part of this great community of nice, caring individuals I continue to come back to contribute and participate however I can.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/njOfL2BcWWQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/7046655929455734223?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/7046655929455734223?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/njOfL2BcWWQ/a-decade-of-commits.html" title="A decade of commits" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2013/04/a-decade-of-commits.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYNSX8-cSp7ImA9WhBWGE0.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-3444039581303271459</id><published>2013-04-12T14:29:00.002-07:00</published><updated>2013-04-12T14:29:58.159-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-12T14:29:58.159-07:00</app:edited><title>Why I'm signing up for Gittip</title><content type="html">While at PyCon I heard about plans to&amp;nbsp;&lt;a href="https://github.com/rubygems/rubygems.org/pull/505"&gt;integrate Gittip into rubygems.org&lt;/a&gt; and so I decided to have another look at &lt;a href="https://www.gittip.com/"&gt;Gittip&lt;/a&gt;. For those that don't know, it's a website where you can give and/or receive money to/from others on a weekly basis. You can give as little as $0.25/week ($13/year) up to $24/week ($1,248/year). Being on a weekly schedule allows you to say "I appreciate the time and effort you put into open source; keep it up!", compared to bounties which are goal-specific and don't recognize people who make contributions that have no direct financial benefit or make contributions year-round.&lt;br /&gt;
&lt;br /&gt;
As I was poking around the site I noticed that my friend &lt;a href="https://www.gittip.com/jnoller/"&gt;Jesse Noller&lt;/a&gt; was the top recipient. I read his page on Gittip which listed his vast accomplishments that he has made in his spare time for no pay beyond gratitude from others and any feeling of accomplishment his hard work gives him. But the other thing his Gittip page mentions is what receiving tips means for him.&lt;br /&gt;
&lt;br /&gt;
It basically boils down to a way for people to thank his family for letting him do his open source work. That sentiment really struck a cord with me. Like most open source contributors, I do it because I derive some enjoyment from it. It's a feeling of accomplishment, it's the&amp;nbsp;camaraderie&amp;nbsp;with my various friends that I have in the Python community, etc. In other words it's all very intangible but I do get something from doing my open source work.&lt;br /&gt;
&lt;br /&gt;
But my family doesn't get any of the benefit that I get. Since I am not paid to do my open source work I need to take personal time to do it. That means I have to take time away from my wife to do this rather solitary work of contributing to open source. While my wife understands why I do what I do for Python, her benefit of getting to be proud of me is indirect and very diluted compared to what I get from it (although she is starting to increase her participation by attending PyCon).&lt;br /&gt;
&lt;br /&gt;
But having people express gratitude through Gittip gives more direct benefit to one's family. When I asked on &lt;a href="https://twitter.com/brettsky/status/315145274798534656"&gt;Twitter&lt;/a&gt; and &lt;a href="https://plus.google.com/115362263245161504841/posts/YVh273ntVVP"&gt;Google+&lt;/a&gt; for people to tip Jesse to thank him for all that he does through the year (and especially for PyCon in the past two years), he got a nice bump in his tips, and so he was able to take his daughter and family out bowling that night.&lt;br /&gt;
&lt;br /&gt;
Tips then are a way for the community to thank someone's family for letting them share their loved one with open source. For instance, tips for me would be a way of thanking my wife for letting me spend the hours I do contributing to Python in my various ways by letting me treat my wife to a night out so neither of us has to cook. It also doesn't hurt that it acts like a small form of blackmail; "yes, Andrea, I do need to get this patch in and you should let me put the time in since the Python community treated you to a nice dinner last night" =) .&lt;br /&gt;
&lt;br /&gt;
All of these reasons are why &lt;a href="https://www.gittip.com/brettcannon/"&gt;I'm joining Gittip&lt;/a&gt;. It has actually now reached the point of legitimacy to have &lt;a href="https://www.gittip.com/heroku/"&gt;Heroku&lt;/a&gt; as a company start leaving tips and &lt;a href="https://www.gittip.com/readthedocs/"&gt;Read the Docs&lt;/a&gt; is trying to pay for various expenses through Gittip; it's no longer just a bunch of individuals. So please consider signing up to both receive and send tips if you have the financial means to thank those in open source for their diligent and hard work.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/AjRLdg5TBIY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3444039581303271459?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3444039581303271459?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/AjRLdg5TBIY/why-im-signing-up-for-gittip.html" title="Why I'm signing up for Gittip" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2013/04/why-im-signing-up-for-gittip.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cBRXkzfCp7ImA9WhBQGUw.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-1611226454202982453</id><published>2013-03-21T19:24:00.000-07:00</published><updated>2013-03-21T19:24:14.784-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-21T19:24:14.784-07:00</app:edited><title>PyCon 2013 report</title><content type="html">PyCon 2013 is now over and it was awesome (as usual)! As seems to happen every year, there were a few themes at the conference.&lt;br /&gt;
&lt;h4&gt;
Packaging&lt;/h4&gt;
&lt;div&gt;
For those of you who don't know, people are giving it another go to try and straighten out packaging in the Python world. The difference compared to the previous attempt is that &lt;a href="http://www.boredomandlaziness.org/"&gt;Nick Coghlan&lt;/a&gt;, who is leading this endeavour, is working directly with pre-existing tools to gain consensus on things instead of trying to get the stdlib to handle it all. This means, for instance, he is working with the installer projects (e.g. &lt;a href="http://www.pip-installer.org/en/latest/"&gt;pip&lt;/a&gt;) to agree on what should (and should not) happen in the evolution of packaging. This seems to have done a good job in energizing key people into supporting Nick's overall view (more on that later).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This means the stdlib is not going to try and solve all problems. The current thinking seems to be that the stdlib should house modules for which PEPs exist and then tools are to be built on top of that. This allows for all tools to act on metadata and such in a uniform way, letting them innovate on higher-level details (and keep the stdlib out of the installer game). Think PEPs &lt;a href="http://python.org/dev/peps/pep-0425/"&gt;425&lt;/a&gt;, &lt;a href="http://python.org/dev/peps/pep-0426/"&gt;426&lt;/a&gt;, and &lt;a href="http://python.org/dev/peps/pep-0427/"&gt;427&lt;/a&gt; details being handled by &lt;a href="http://distlib.readthedocs.org/en/latest/"&gt;distlib&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
He is also working from the top down on the stack. This means installer now, build-related stuff later. This has the nice benefit that the thing that most people directly interact with the most should get fixed first, rather than worrying about behind-the-scenes details later.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
What does all of this mean? Eventually people will be able to get an installer, be able to securely install from the &lt;a href="https://cheeseshop.python.org/"&gt;Cheeseshop&lt;/a&gt; (or any other package index of their choosing), and have it all bootstrap up on their system easily. A proposal (&lt;a href="http://python.org/dev/peps/pep-0439/"&gt;PEP 439&lt;/a&gt;) even went out this week to basically include a pip bootstrap script in Python which will install the real pip if it has not already happened and then continue on with the installation, making it all seamless. You can follow the &lt;a href="http://mail.python.org/pipermail/distutils-sig/2013-March/020185.html"&gt;discussion of this specific proposal&lt;/a&gt; on &lt;a href="http://mail.python.org/mailman/listinfo/distutils-sig"&gt;distutils-sig&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If all of this interests you I suggest you watch the &lt;a href="https://us.pycon.org/2013/schedule/presentation/34/"&gt;packaging panel&lt;/a&gt; when the video goes up.&lt;/div&gt;
&lt;h4&gt;
Python 3.3&lt;/h4&gt;
&lt;div&gt;
I gave my Python 3.3 &amp;gt; Python 2.7 talk again (video &lt;a href="http://pyvideo.org/video/1730/python-33-trust-me-its-better-than-27"&gt;here&lt;/a&gt;; &lt;a href="http://www.youtube.com/watch?v=Ebyz66jPyJg&amp;amp;list=PLkuS0waF8krgk1ULTg6sGrEBMs46AfoMt&amp;amp;index=6"&gt;PyCon Argentina video here&lt;/a&gt; although I think I like the US one more) where basically I pointed out all the wonderful features of Python 3.3 and that performance-wise you don't have to care which version you use (unless you have memory issues in which case you will want to use Python 3.3). I honestly was expecting some pushback since I have become a little jaded over the past 4+ years of Python 3's existence. But you know what? No pushback at all (but maybe it's because &lt;a href="http://lucumr.pocoo.org/"&gt;Armin&lt;/a&gt; wasn't there this year =). It was a really nice change of pace to not have to defend something I believe in and have worked hard to foster.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I heard numerous people tell me that they had finally been able to start using Python 3 and that they really enjoyed it. &lt;a href="http://jacobian.org/"&gt;Jacob Kaplan-Moss&lt;/a&gt; of &lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; fame gave a talk on &lt;a href="https://us.pycon.org/2013/schedule/presentation/97/"&gt;porting Django apps to Python 3&lt;/a&gt;&amp;nbsp;(no video yet) and told me that he not only liked Python 3, but that the no-argument version of &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt; made him "irrationally excited". &lt;a href="http://www.dabeaz.com/"&gt;David Beazley&lt;/a&gt; said that since he wrote the &lt;a href="http://shop.oreilly.com/product/0636920027072.do"&gt;3rd edition of the Python Cookbook&lt;/a&gt; for Python 3.3 he finds Python 2.7 a bit painful to use. It continues to be the case that almost everyone who gives Python 3 a fair shake ends up really liking it.&lt;/div&gt;
&lt;div&gt;
&lt;h4&gt;
Diversity &amp;amp; Outreach&lt;/h4&gt;
&lt;div&gt;
Watch &lt;a href="http://pyvideo.org/video/1848/opening-statements"&gt;Jesse Noller's opening statements&lt;/a&gt;. Then watch &lt;a href="http://pyvideo.org/video/1668/keynote-2"&gt;Eben Upton's keynote&lt;/a&gt;. Then realize that 20% of attendees were women. Then realize there was also a Raspberry Pi programming class for kids. Then really make sure you watch Jesse's opening statements if you ignored that initial link. Makes me want to be a better person and try to help people even more.&lt;/div&gt;
&lt;/div&gt;
&lt;h4&gt;
Everything else&lt;/h4&gt;
&lt;div&gt;
I gave my "How Import Works" talk (US video &lt;a href="http://pyvideo.org/video/1707/how-import-works"&gt;here&lt;/a&gt;, Argentina video &lt;a href="http://www.youtube.com/watch?v=Nsg886UOahw&amp;amp;list=PLkuS0waF8krjwcRHzSJMq_nA67mCFi24T&amp;amp;index=11"&gt;here&lt;/a&gt; and this time I prefer the latter thanks to having more time and thus feeling more relaxed).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The language summit happened. You can find numerous other summaries of what happend out there (&lt;a href="http://python-notes.boredomandlaziness.org/en/latest/conferences/pyconus2013/20130313-language-summit.html"&gt;Nick Coghlan&lt;/a&gt;, &lt;a href="http://kushaldas.in/posts/notes-from-language-summit-at-pycon.html"&gt;Kushal Das&lt;/a&gt;), so I won't rehash it here.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I wasn't able to stick around for the sprints this year (first time since the founding of the conference) past half of the first day. But hopefully next year I will be able to make it work out.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As I said, overall it was a great conference. Thanks to Jesse and everyone else who volunteered to help make it a great week.&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/MIyC-DoYNg8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/1611226454202982453?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/1611226454202982453?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/MIyC-DoYNg8/pycon-2013-report.html" title="PyCon 2013 report" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2013/03/pycon-2013-report.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUNRHgzeSp7ImA9WhBSEkw.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-4408282671374803347</id><published>2013-02-17T10:45:00.000-08:00</published><updated>2013-02-18T09:58:15.681-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-18T09:58:15.681-08:00</app:edited><title>Resolving a TOOWTDI interface problem for attributes</title><content type="html">&lt;b&gt;TL;DR&lt;/b&gt;: choose one way to signify the lack of information in an API either as making the attribute optional or setting a default value (e.g.&amp;nbsp;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt;), but not both.&lt;br /&gt;
&lt;br /&gt;
When you read the docs for &lt;a href="http://docs.python.org/3/library/importlib.html#importlib.find_loader"&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;importlib.find_loader()&lt;/span&gt;&lt;/a&gt; you find that an exception is raised when &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__loader__&lt;/span&gt; is set to &lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt;. But if you read the docs for &lt;a href="http://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module"&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;importlib.abc.Loader.load_module()&lt;/span&gt;&lt;/a&gt; you will notice that &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__loader__&lt;/span&gt; "&lt;i&gt;should&lt;/i&gt; be set" (italics mine). So one part of the docs says having a value of &lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt; is fine while another says the attribute doesn't even have to exist. So the former is a LBYL version of the API while the latter is a EAFP version. While that's technically fine, I do like the concept of TOOWTDI in Python, so I would prefer choosing one of the approaches as the definitive way to signal that a module's loader is not known.&lt;br /&gt;
&lt;br /&gt;
Does long-term (think in timescales of years) backwards-compatibility suggest a preference of one over the other? As it stands now, one must do:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;
if getattr(module, '__loader__', None) is not None:&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; # Use loader&amp;nbsp;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
That handles both the LBYL and EAFP approaches of either not setting the attribute or setting it to &lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt;. If this were to translate to LBYL it would become:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;
if module.__loader__ is not None:
&lt;/code&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; # Use loader&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Not a huge difference, just easier to read. The EAFP approach would be:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: monospace;"&gt;try:&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: monospace;"&gt;&amp;nbsp; loader = module.__loader__&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: monospace;"&gt;except AttributeError:&lt;br /&gt;&amp;nbsp; pass&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: monospace;"&gt;else:&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: monospace;"&gt;&amp;nbsp; # Use loader&lt;/span&gt;&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;&lt;/code&gt;
Longer, but still totally readable and psychologically makes more sense since the attribute is set more often than not (importlib actually sets the attribute along with __package__ after importing if they are not already set).&lt;br /&gt;
&lt;br /&gt;
But since most code that cares whether &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__loader__&lt;/span&gt; is set already uses the &lt;span style="font-family: Courier New, Courier, monospace;"&gt;getattr()&lt;/span&gt; approach, the &lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt; value approach is the least disruptive to changing to the eventual idiom.&lt;br /&gt;
&lt;br /&gt;
But the thing that tipped the scales for me is I don't want the attribute to be optional but be required in the long run (think Python 4 long run; side-effect of how long Python versions last), so I plan to change the default attributes on the module type to always have &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__loader__&lt;/span&gt; and &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__package__&lt;/span&gt; and set them to &lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt; by default in Python 3.4. That means the optional approach won't mean anything going forward, so that makes the LBYL approach the one I plan to go with even if I personally prefer the EAFP approach for optional API attributes; I don't want this part of the API being viewed as optional by loader authors.&lt;br /&gt;
&lt;br /&gt;
If you care about any of this specific API cleanup, you can follow &lt;a href="http://bugs.python.org/issue17115"&gt;issue #17115&lt;/a&gt; as I clean up importlib's mixed approach to &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__loader__&lt;/span&gt;.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/x09zmYrwpHk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/4408282671374803347?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/4408282671374803347?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/x09zmYrwpHk/resolving-toowtdi-interface-problem-for.html" title="Resolving a TOOWTDI interface problem for attributes" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2013/02/resolving-toowtdi-interface-problem-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQGSX05eyp7ImA9WhNaF0g.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-895530108281744477</id><published>2013-02-01T13:00:00.000-08:00</published><updated>2013-02-01T14:22:08.323-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-01T14:22:08.323-08:00</app:edited><title>Remember that the "BC" in ABC means "Base Class"</title><content type="html">[UPDATE: had a talk with &lt;a class="g-profile" href="http://plus.google.com/100617505900164826251" target="_blank"&gt;+Thomas Wouters&lt;/a&gt;&amp;nbsp;on IM and has caused me to rethink things. New thoughts up top, original post after the jump break]&lt;br /&gt;
&lt;br /&gt;
I had mis-heard a comment Thomas Wouters&amp;nbsp;made in a meeting about not raising &lt;span style="font-family: Courier New, Courier, monospace;"&gt;&lt;a href="http://docs.python.org/3/library/exceptions.html?highlight=notimplementederror#NotImplementedError"&gt;NotImplementedError&lt;/a&gt;&lt;/span&gt; and using &lt;a href="http://docs.python.org/3/library/abc.html#module-abc"&gt;ABCs&lt;/a&gt;, which led to me thinking about the problem of having ABCs in your &lt;a href="http://docs.python.org/3/glossary.html#term-method-resolution-order"&gt;MRO&lt;/a&gt; which were not at the bottom &lt;b&gt;and&lt;/b&gt;&amp;nbsp;defined methods which would override methods you wanted to access farther down the inheritance chain. I had thought that calling &lt;span style="font-family: Courier New, Courier, monospace;"&gt;&lt;a href="http://rhettinger.wordpress.com/2011/05/26/super-considered-super/"&gt;super()&lt;/a&gt;&lt;/span&gt; in your ABCs in some manner was the solution. But after discussing things with Thomas I believe I was in the wrong and I had badly misheard what he had said. =)&lt;br /&gt;
&lt;br /&gt;
Because &lt;a href="http://docs.python.org/3/library/importlib.html#module-importlib.abc"&gt;importlib has a bunch of overlapping ABCs&lt;/a&gt; which inherit from each other I thought that the situation might come up where you inherited from two different classes which had overlap in methods but for which you would want them to build off of each other. But as Thomas pointed out to me, ABCs are meant to be at the bottom of an MRO; the BC stands for "Base Class" for a reason. If you are trying to interleave methods between two different classes implementing the same interface then either the granularity of the ABC is wrong or you shouldn't be inheriting from the ABC to begin with. I tried to come up with counter-examples but they were so convoluted and leading to bad API design in order to justify that I gave up and admitted they were stupid.&lt;br /&gt;
&lt;br /&gt;
What does all of this mean for you when you are writing an ABC? You should just treat your ABCs as the bottom of your MRO. That means you should have all of your methods, even the abstract ones, do something sensible in case they are somewhat blindly reached through a &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt; call. If you have a default return value, return that. If that does not exist then you should raise the exception which signifies failure as defined by the API. But raising &lt;span style="font-family: Courier New, Courier, monospace;"&gt;NotImplementedError&lt;/span&gt; is not the right thing to do when it can be avoided with a sensible default reaction (which I have not been doing in &lt;span style="font-family: Courier New, Courier, monospace;"&gt;importlib.abc&lt;/span&gt;). This also has a nice side benefit of making sure you clearly define what the default reaction is for a call to the method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;[ORIGINAL POST]&lt;br /&gt;
&lt;br /&gt;
I was in a meeting yesterday with Google's Python team and the point of using &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt; in a base class and not raising &lt;span style="font-family: Courier New, Courier, monospace;"&gt;NotImplementedError&lt;/span&gt; came up. Thomas Wouters&amp;nbsp;said you should always use it and that he would discuss it with the other engineer offline as the rest of us "already knew what to do". And that's when I realized I had forgotten do use &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt; in &lt;a href="http://docs.python.org/3/library/importlib.html#module-importlib.abc"&gt;importlib.abc&lt;/a&gt;&amp;nbsp;and was doing exactly what I shouldn't be. Lesson learned: code you work on over the span of five years may not follow best practices. =)&lt;br /&gt;
&lt;br /&gt;
If you don't have much experience with super(), read &lt;a href="http://rhettinger.wordpress.com/2011/05/26/super-considered-super/"&gt;the post&lt;/a&gt; by&amp;nbsp;&lt;a class="g-profile" href="http://plus.google.com/107797496464450630987" target="_blank"&gt;+Raymond Hettinger&lt;/a&gt;&amp;nbsp;which explains best practices. Unfortunately it doesn't cover &lt;a href="http://docs.python.org/3/library/abc.html#module-abc"&gt;ABC&lt;/a&gt;s which have their own set of best practices in terms of &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt;. In a nutshell, because multiple inheritance doesn't guarantee that you will be the bottom of the &lt;a href="http://docs.python.org/3/glossary.html#term-method-resolution-order"&gt;MRO&lt;/a&gt; even when it comes to ABCs, you should expect to have every method which doesn't actually implement anything fall through using super() when appropriate. E.g. if a method's return value doesn't have a sensible default (e.g. it's not all about the side-effects), then you should blindly call &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt;, else call &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super()&lt;/span&gt; only when it won't fail.&lt;br /&gt;
&lt;br /&gt;
To illustrate, let's work with &lt;a href="http://hg.python.org/cpython/file/905b4e3cf6d0/Lib/importlib/abc.py#l45"&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;importlib.abc.MetaPathFinder&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(and I should mention all code samples in this post are assumed for Python 3):&lt;br /&gt;
&lt;br /&gt;
&lt;ol style="background-color: #f8f8f8; color: #acacac; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace, serif; font-size: 12px; line-height: 21px; margin: 0px; padding: 0px 0px 0px 48px;"&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;MetaPathFinder&lt;span class="br0"&gt;(&lt;/span&gt;Finder&lt;span class="br0"&gt;)&lt;/span&gt;:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="sy0" style="color: #66cc66;"&gt;@&lt;/span&gt;abc.&lt;span class="me1"&gt;abstractmethod&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;def&lt;/span&gt;&amp;nbsp;find_module&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="kw2" style="color: green;"&gt;self&lt;/span&gt;&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;fullname&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;path&lt;span class="br0"&gt;)&lt;/span&gt;:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="st0" style="color: darkslateblue;"&gt;"""Abstract method which, when implemented, should find a module.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="st0" style="color: darkslateblue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;The fullname is a str and the path is a str or None.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="st0" style="color: darkslateblue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Returns a Loader object.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="st0" style="color: darkslateblue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;"""&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;raise&lt;/span&gt;&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;def&lt;/span&gt;&amp;nbsp;invalidate_caches&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="kw2" style="color: green;"&gt;self&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="st0" style="color: darkslateblue;"&gt;"""An optional method for clearing the finder's cache, if any.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="st0" style="color: darkslateblue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;This method is used by importlib.invalidate_caches().&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="st0" style="color: darkslateblue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;"""&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;NotImplemented&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
What is wrong with this code? To start, what happens if I call &lt;span style="font-family: Courier New, Courier, monospace;"&gt;MetaPathFinder.find_module()&lt;/span&gt; as part of a chain of super() calls? I get an exception, which is not really acceptable if this ABC is not at the bottom of the MRO for a class since a proper return value is expected for the method (one could argue that returning None is an acceptable default result in this specific instance, but a finder which never finds anything makes no sense in general so I'm not even entertaining that idea). What should really happen is &lt;span style="font-family: Courier New, Courier, monospace;"&gt;return super().find_module(fullname, path)&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;. That way if someone calls this method in hopes of reaching a &lt;/span&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;find_module()&lt;/span&gt;&lt;span style="font-family: inherit;"&gt; method farther down the MRO then they will be able to. And if no such method is defined? They still get an exception (albeit a different one) and so the (rough) semantics stay the same. Granted, most times this MRO will be the second-to-last class in an MRO (&lt;/span&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;object&lt;/span&gt;&lt;span style="font-family: inherit;"&gt; is always last), but this is still an improvement worth making just in case.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style="font-family: inherit;"&gt;What about &lt;/span&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;MetaPathFinder.invalidate_caches()&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;? That has no&amp;nbsp;&lt;/span&gt;discernible&lt;span style="font-family: inherit;"&gt;&amp;nbsp;return value (the method is all about its side-effects when implemented), so we don't have to worry about a call being a no-op as that is an acceptable result. That means &lt;/span&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;invalidate_caches()&lt;/span&gt;&lt;span style="font-family: inherit;"&gt; should turn into:&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;ol style="background-color: #f8f8f8; color: #acacac; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace, serif; font-size: 12px; line-height: 21px; margin: 0px; padding: 0px 0px 0px 48px;"&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="kw2" style="color: green;"&gt;super&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class="sy0" style="color: #66cc66;"&gt;=&lt;/span&gt;&amp;nbsp;super_&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;if&lt;/span&gt;&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;hasattr&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;super_&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span class="st0" style="color: darkslateblue;"&gt;'invalidate_caches'&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;super&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;.&lt;span class="me1"&gt;invalidate_caches&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="co1" style="color: grey; font-style: italic;"&gt;# Or as a one-liner&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;getattr&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="kw2" style="color: green;"&gt;super&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span class="st0" style="color: darkslateblue;"&gt;'invalidate_caches'&lt;/span&gt;&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;lambda&lt;/span&gt;:&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;None&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
This then allows the no-op to occur if there is no one else to fall-through to, else the fall-through is allowed without error (I'm also relying on Python's semantics of returning &lt;span style="font-family: Courier New, Courier, monospace;"&gt;None&lt;/span&gt; by default plus the semantics of the method not having an important return value).&lt;br /&gt;
&lt;br /&gt;
One method that can be a little sticky if not handled properly is the &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__init__()&lt;/span&gt; method. If you read Raymond's blog post you will notice he recommends that you strip off arguments as they are consumed so that when you hit near the bottom of your MRO there are no arguments, letting it hit &lt;span style="font-family: Courier New, Courier, monospace;"&gt;object.__init__()&lt;/span&gt; which takes no arguments. But if you don't do that and don't pay attention to where you are in the MRO you can easily pass something to &lt;span style="font-family: Courier New, Courier, monospace;"&gt;object.__init__()&lt;/span&gt; and get a &lt;span style="font-family: Courier New, Courier, monospace;"&gt;TypeError&lt;/span&gt;. As a challenge I decided to see if I could solve the problem somehow with code instead of convention and I came up with:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ol style="background-color: #f8f8f8; color: #acacac; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace, serif; font-size: 12px; line-height: 21px; margin: 0px; padding: 0px 0px 0px 48px;"&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;def&lt;/span&gt;&amp;nbsp;super___init__&lt;span class="br0"&gt;(&lt;/span&gt;super_&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;*args&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;**kwargs&lt;span class="br0"&gt;)&lt;/span&gt;:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; mro&amp;nbsp;&lt;span class="sy0" style="color: #66cc66;"&gt;=&lt;/span&gt;&amp;nbsp;super_.__self_class__.&lt;span class="me1"&gt;mro&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="co1" style="color: grey; font-style: italic;"&gt;# Check this is not the relevant end of the MRO.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;if&lt;/span&gt;&amp;nbsp;mro&lt;span class="br0"&gt;[&lt;/span&gt;-&lt;span class="nu0" style="color: orangered;"&gt;1&lt;/span&gt;&lt;span class="br0"&gt;]&lt;/span&gt;&amp;nbsp;&lt;span class="sy0" style="color: #66cc66;"&gt;!=&lt;/span&gt;&amp;nbsp;super_.__thisclass__:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp; super_.&lt;span class="kw4" style="color: mediumblue;"&gt;__init__&lt;/span&gt;&lt;span class="br0"&gt;(&lt;/span&gt;*args&lt;span class="sy0" style="color: #66cc66;"&gt;,&lt;/span&gt;&amp;nbsp;**kwargs&lt;span class="br0"&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li2" style="-webkit-user-select: none;"&gt;&lt;div class="de2" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;else&lt;/span&gt;:&lt;/div&gt;
&lt;/li&gt;
&lt;li class="li1" style="-webkit-user-select: none;"&gt;&lt;div class="de1" style="-webkit-user-select: text; background-color: white; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; color: black; margin: 0px 0px 0px -7px; padding: 0px 5px; position: relative; vertical-align: top;"&gt;
&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;assert&lt;/span&gt;&amp;nbsp;mro&lt;span class="br0"&gt;[&lt;/span&gt;-&lt;span class="nu0" style="color: orangered;"&gt;1&lt;/span&gt;&lt;span class="br0"&gt;]&lt;/span&gt;&amp;nbsp;&lt;span class="kw1" style="color: #ff7700; font-weight: bold;"&gt;is&lt;/span&gt;&amp;nbsp;&lt;span class="kw2" style="color: green;"&gt;object&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="co1" style="color: grey; font-style: italic;"&gt;# Always at the bottom.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
This allows you to make a call like &lt;span style="font-family: Courier New, Courier, monospace;"&gt;super___init__(super(), *args, **kwargs)&lt;/span&gt; from within your own &lt;span style="font-family: Courier New, Courier, monospace;"&gt;__init__()&lt;/span&gt; and not have to worry about whether you have properly stripped everything out of &lt;span style="font-family: Courier New, Courier, monospace;"&gt;args&lt;/span&gt; and &lt;span style="font-family: Courier New, Courier, monospace;"&gt;kwargs&lt;/span&gt;. Now I don't necessarily recommend doing this instead of continually stripping arguments, but this could help in situations where you would have an adapter class instead to catch the bottom of the MRO from calling into &lt;span style="font-family: Courier New, Courier, monospace;"&gt;object.__init__()&lt;/span&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;(I suspect Raymond didn't suggest this over adapter classes as it won't work with classic classes in Python 2).&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/zNmDe0CZiSs" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/895530108281744477?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/895530108281744477?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/zNmDe0CZiSs/remember-to-use-super-in-your-abcs.html" title="Remember that the &quot;BC&quot; in ABC means &quot;Base Class&quot;" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2013/02/remember-to-use-super-in-your-abcs.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEBRH08eCp7ImA9WhNWEEo.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-2496748397300943570</id><published>2012-12-09T10:44:00.001-08:00</published><updated>2012-12-09T10:44:15.370-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-09T10:44:15.370-08:00</app:edited><title>How much of Python can be written in Python?</title><content type="html">&lt;br /&gt;
Now I don't mean in the PyPy sense where you can bootstrap yourself with another Python installation. No, I'm talking about all you have is a checkout of the&amp;nbsp;&lt;a href="http://hg.python.org/cpython"&gt;CPython repository&lt;/a&gt;&amp;nbsp;and a&amp;nbsp;&lt;a href="http://clang.llvm.org/"&gt;C compiler&lt;/a&gt;. How far could you go in writing stuff for Python in Python and not C (from my perspective, for maintainability, for others perhaps ease of extensibility). In Python 3.3 we now have import written in Python (technically the main import loop that is used is implemented in C to save 5% at startup, but that is entirely optional as equivalent pure Python code still exists) and it's actually faster than the C version from Python 3.2 thanks to directory content caching. So it is not entirely ridiculous to think about how far one could push the idea of replacing C code in CPython with Python code.&lt;br /&gt;
&lt;br /&gt;
What restrictions do we have for this thought experiment? One is that CPython needs to continue to be performant. That means either that the feature is not executed constantly or can be made to work as close to C code as possible.&amp;nbsp;The other requirement is that it can't really have dependencies on the stdlib beyond built-in modules. Since this concept works based on freezing Python bytecode into C-level char arrays you don't want to have to pull in half the stdlib just to make something work. But that's pretty much it.&lt;br /&gt;
&lt;br /&gt;
The first possibility is the parser. If you either generated the parser like the one CPython uses (that has not really changed much since Guido wrote it way back when) or wrote a recursive descent one by hand, it could probably be written in Python. The real problem is how performance might be hit. Now if you are working off of bytecode files then this really is only a one-time cost per bytecode file creation. But if you are working primarily with modules that you specify on the command line then they get parsed every time you invoke the interpreter and that could be costly if you can't get performance to be good enough.&lt;br /&gt;
&lt;br /&gt;
Going down the compiler chain, you could also go from CST (concrete syntax tree) to AST (abstract syntax tree) in pure Python. You can already get to the CST from the&amp;nbsp;&lt;a href="http://docs.python.org/3/library/parser.html#module-parser"&gt;parser module&lt;/a&gt;, so the work to expose the CST at the Python level is done. And with the&amp;nbsp;&lt;a href="http://docs.python.org/3/library/ast.html#module-ast"&gt;ast module&lt;/a&gt;&amp;nbsp;already exposed it then becomes a matter of creating the AST nodes from the CST. But once again, it's a question of performance since this is invoked every time source code is compiled.&lt;br /&gt;
&lt;br /&gt;
Next would be transforming the AST to bytecode. The AST is already exposed to Python code, so once again the initial work is done for access. But also once again there is the question of performance as this is also on the critical path if you continually compiling Python source code because you are executing scripts instead of importing code which was previously stored as a bytecode file.&lt;br /&gt;
&lt;br /&gt;
You can't do anything for the interpreter eval loop as that becomes a bootstrap issue. If you really wanted to push this you could do a basic eval loop to bootstrap a more complex one, but that seems like more work than it's worth.&lt;br /&gt;
&lt;br /&gt;
I suspect most of Python's builtins could be re-implemented in pure Python without any trouble. Re-implementing something like any(), map(), etc. is not exactly difficult.&amp;nbsp;In this instance, though, performance definitely becomes a key issue due to the extensive use of builtin functions. And in the case of exceptions you have to worry about the C API surrounding them on top of any possible performance issue from exception raising (although I'm willing to bet this can easily be alleviated by just caching at the interpreter level the builtin exception classes so that at the C level it's still just PyObject pointers instead of having to extract them dynamically every time from the builtin module).&lt;br /&gt;
&lt;br /&gt;
And as always every single module in the stdlib does not have to be implemented in C code if it doesn't wrap other C code. In that instance it is simply taking the time to either copy over and get working the pure Python versions of modules that other VMs have written or writing one from scratch. But thanks to&amp;nbsp;&lt;a href="http://python.org/dev/peps/pep-0399/"&gt;PEP 399&lt;/a&gt;&amp;nbsp;this is only an issue for pre-existing modules (which is also why no one has bothered to backfill all of those modules as the other VMs have already done the work for themselves so no one really needs this to happen; I opened&amp;nbsp;&lt;a href="http://bugs.python.org/issue16651"&gt;issue 16651&lt;/a&gt;&amp;nbsp;to find out exactly what modules don't have a pure Python version).&lt;br /&gt;
&lt;br /&gt;
In other words, there are various possibilities for technically writing more of CPython in pure Python exists, but performance considerations will quite possibly not make it worth pursuing (but I would be quite happy if proved wrong =).&lt;br /&gt;
&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/Swj-bUwC6FY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/2496748397300943570?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/2496748397300943570?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/Swj-bUwC6FY/how-much-of-python-can-be-written-in.html" title="How much of Python can be written in Python?" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/12/how-much-of-python-can-be-written-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkENRn4zeip7ImA9WhVVGUs.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-2969136173953826690</id><published>2012-05-13T21:11:00.002-07:00</published><updated>2012-05-13T21:11:37.082-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-13T21:11:37.082-07:00</app:edited><title>My (very shallow) thoughts on Dart</title><content type="html">Being the language nerd that I am, I actually find it fun to learn new programming languages. Now typically this is nothing more than me reading all of the official documentation and writing some toy examples that give me a very shallow, quick-and-dirty feel for a language. Since I have been involved in language design for nearly a decade (started participating on python-dev in June 2002) and have done toy examples now in &lt;a href="http://code.google.com/p/bcannon/source/browse/#hg%2Flanguages"&gt;18 languages&lt;/a&gt; (17 actually still run; I have never bothered to get Forth to work again after a gforth change broke my code),&amp;nbsp;this is actually usually enough for me to grasp the inspirations for a language and thus understand its essence.&lt;br /&gt;
&lt;br /&gt;
At work I have been doing some JavaScript work for an internal Chrome extension and dashboard and so that led me to want to look into what &lt;a href="http://www.dartlang.org/"&gt;Dart&lt;/a&gt; had to offer over JavaScript. I know the language is only at version 0.09 (and still changing weekly), but the fundamentals are there so I wanted to see what the general feel of the language is (and will continue to be).&lt;br /&gt;
&lt;br /&gt;
I also know Dart is &lt;a href="https://news.ycombinator.com/item?id=2982949"&gt;somewhat controversial&lt;/a&gt; for some people. Personally, I fall on the &lt;a href="http://www.dartlang.org/support/faq.html#does-dart-divert-effort"&gt;"competition is good" side&lt;/a&gt; of the argument, not the "OMG fragmentation" side. I want ECMAScript Harmony to still happen and give me a cleaner, tighter, more functional JavaScript, but that doesn't mean Dart doesn't have a place in the world as a cleaner OO language for the web. Besides, me thinking otherwise would make me a massive hypocrite as I began working on Python before it was cool (I feel like I need a hipster meme for that statement, but I digress) and I have worked hard to convert people to Python from other languages. Hell, I have tried to foster competition between the Python VMs to get them to push each other to perform better and be ever more interoperable. IOW I don't totally buy this fragmentation argument.&lt;br /&gt;
&lt;br /&gt;
Going into learning Dart I knew who was involved with the language which is what will inherently define how a language feels. I knew &lt;a href="http://en.wikipedia.org/wiki/Lars_Bak_(computer_programmer)"&gt;Lars Bak&lt;/a&gt; of &lt;a href="http://code.google.com/p/v8/"&gt;V8&lt;/a&gt; helped design the language, which meant it would have some design restrictions put on it to make it have a damn fast VM. &lt;a href="http://en.wikipedia.org/wiki/Joshua_Bloch"&gt;Josh Bloch&lt;/a&gt; has been helping to design Dart's library which meant some JDK feel to it. I also know Jim Hugunin is involved which should also help with the VM speed. So fast with an API designed like the JDK.&lt;br /&gt;
&lt;br /&gt;
What did I find? A language with a damn fast VM and a standard library that felt like the JDK. =) Take OO as a Python programmer would expect (e.g. pure OO where everything is an object, not dogmatic OO like Java where everything has to be in an class definition), make types entirely optional for testing and tooling purposes but enough support to use interfaces and generics, and then toss in abilities based on what JavaScript allows and then you have a good idea of what Dart offers.&lt;br /&gt;
&lt;br /&gt;
So, Dart has optional typing. In case you have not heard, Dart does not use type information at runtime for performance and only throws any form of fit if a type doesn't match what is specified unless you run in &lt;i&gt;checked&lt;/i&gt;&amp;nbsp;mode. If you do that then you get warnings about possible type issues. But &lt;a href="http://www.dartlang.org/support/faq.html#why-types-unsound"&gt;Dart's type system is unsound&lt;/a&gt; so don't expect typing to catch every error that a more strict type system might even when you run in checked mode. Dart views types as helpful documentation and a way to help tools assist with things, period. I actually find it rather refreshing to have a language that treats types as just documentation since that is really what they are for the programmer (VMs can use it for performance, but it isn't required for good performance and type safety only saves you from a minor set of bugs which every Python programmer probably realizes eventually =).&lt;br /&gt;
&lt;br /&gt;
But that's even if you bother with types! You can write all of your code without types and everything will run without issue. Even generics are optional, so you can declare a function accepts a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt; or &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;int&gt;&lt;/int&gt;&lt;/span&gt;; Dart doesn't care either way and it alleviates covariance/contravariance headaches by not caring if you don't care either. It's actually rather nice to have non-library code be written quickly using dynamic typing and only add in the type information for library code where you care about what interface is expected. IOW I think Dart strike a nice balance with how it does typing and I actually feel fine using types when I know what I expect to accept in my own code that I don't expect anyone else to rely upon.&lt;br /&gt;
&lt;br /&gt;
Dart is OO, not prototypical like JavaScript. It's single-inheritance, which I'm fine with. It does have interfaces as one would expect in a statically typed language, but it softens their expense by allowing one to define a default implementation of an interface. What this means is that the Map interface will also give you a HashMap instance if you call &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;new Map()&lt;/span&gt;&lt;span style="background-color: white; font-family: inherit;"&gt;. I suspect they snagged the idea from Scala &amp;nbsp;where you have the Map class which hides HashMap from the user if you simply don't care about what Map implementation you use.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;It does have a modicum of privacy by using a leading underscore for signaling something is private, much like Python. But the privacy is enforced at the library-level or is public, period. Every field automatically has a getter and setter defined for them, so there is no way to force a private field (which I think is a good thing since I find private privacy bloody annoying). I also like that getters and setters are directly supported by the language with automatic generation show you don't ever have to see a setSomething()/getSomething() function call just to read/write a field, but you can do something like Python's properties very easily.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;The standard libraries are fine and just feel like the JDK. Things are very much LBYL rather than EAFP. I am willing to bet (although I have not tested this) that exceptions are a little expensive in Dart (since exceptions are hard to optimize) and so they would rather go the LBYL way. But they still went a little overboard in my opinion on some things (e.g. the &lt;a href="http://api.dartlang.org/dart_core/List.html"&gt;list interface&lt;/a&gt; has a last() method instead of supporting negative indexes). But there is nothing there that is making me run away screaming.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;One place I do think Dart could use some improvement is simplifying their constructor rules. Upfront Dart has some nice syntactic sugar for a construction where you directly specify how a constructor's arguments map to instance fields, avoiding having to declare the constructor parameters and then also write an assignment. OK, I like that.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;Dart also has initializer lists which let you initialize final fields. OK, that's cool and a nice idea taken from C++.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; font-family: inherit;"&gt;Constructors are not inherited. OK, that's fine since you probably want to be explicit about how you tweak stuff. But there is an exception about the default, no-argument constructor calling the superclass' no-argument constructor. So while not technically inherited, it might as well be in that single instance. And all defined constructors will automatically call the default constructor, which if it isn't defined you must explicitly call a constructor somehow (probably in the initializer list of your constructor). Um, OK...&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And you have named constructors. This gets you around from the lack of type-based method overloading for constructors. OK, I can go with that.&lt;br /&gt;
&lt;br /&gt;
You also have constant constructors since fields can only be initialized to compile-constant values. Fine, that's for performance and determinism in instance creation, so I can grasp the desire for that.&lt;br /&gt;
&lt;br /&gt;
And then you have factory constructors. OK, this is where I go "WTF people". This is so that you can have a constructor that actually doesn't create a new instance but instead can return something else other than a new instance (think of Python's __new__() or any of Java's static factory methods). But this lets you use the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;new&lt;/span&gt; keyword on a factory constructor instead of using a static method. And that to me seems unneeded.&lt;br /&gt;
&lt;br /&gt;
So lets recap what constructor options we have. We have regular constructors, default and defined, which supports initialize lists. You have named constructors. There are constant constructors. And you also have factory constructors. If you don't count the default constructor as special that means Dart has four types of constructors. WTF!?! I realize that Java's FactoryFactoryOfFactories crap has probably spooked the crap out of the Dart designers, all the while having Java influences making them think they need the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;new&lt;/span&gt; keyword for anything that would return an instance of a class, but this seems a bit much. Dart's function definitions are rich enough to allow for optional arguments, etc. which would suggest that the typical constructor can do the job of named constructors with static methods picking up the slack where absolutely necessary where factory constructors are used. Maybe I'm missing something here, but I think they tried to design for everything that is bad about Java's constructor mess without stopping to think what their function definitions already buy them, all while making sure the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;new&lt;/span&gt; keyword was used.&lt;br /&gt;
&lt;br /&gt;
Luckily that is the only bit of Dart that I found poorly designed. Everything else is reasonable and something any JavaScript programmer will be somewhat familiar with or quickly grasp.&lt;br /&gt;
&lt;br /&gt;
Now as I said, I only did &lt;a href="http://code.google.com/p/bcannon/source/browse/#hg%2Flanguages%2FDart"&gt;toy examples in Dart&lt;/a&gt; beyond reading the docs from beginning to end. If I had more time this weekend I may have done one more coding example that was more involved, but I ran out of time. But based on what I have read and what I learned, I am happy with Dart and would be content in using it for programming for the Internet. I would also be totally happy being asked to use it in a situation where others wanted to use types (e.g. I would be fine ditching Java for Dart if people really felt the need to hold on to their types).&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/p0VhUiNzBpI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/2969136173953826690?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/2969136173953826690?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/p0VhUiNzBpI/my-very-shallow-thoughts-on-dart.html" title="My (very shallow) thoughts on Dart" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/05/my-very-shallow-thoughts-on-dart.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4BRHw-cCp7ImA9WhVVGEg.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-1179193750413927939</id><published>2012-05-12T13:02:00.002-07:00</published><updated>2012-05-12T13:02:35.258-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-12T13:02:35.258-07:00</app:edited><title>Thoughts on using function signatures as a DSL for CLI parsers</title><content type="html">I have no idea why, but this morning I thought about a decorator for delineating what function should be treated as the main function (e.g. using a decorator instead of the traditional &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;if __name__ == '__main__'&lt;/span&gt; idiom). Now I solved it in my head on the spot, and then immediately realized someone had to have solved this already. Turns out various people have done things as nuts as examine stack levels to detect the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;__main__&lt;/span&gt; name, but the most straight-forward &lt;a href="http://code.activestate.com/recipes/577791/"&gt;solution&lt;/a&gt; I found doesn't do anything nearly as nuts or CPython-specific and is basically what I came up with. There was a red herring, though, in everyone's solution where they claim the decorator has to be on the last function in your module. While technically true when using the decorator as a decorator only, you can also just as easily not decorate the function and instead, at the end of your module, do something like &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;main(func)&lt;/span&gt; since that is the same as decorating &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;func&lt;/span&gt; with &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;main&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
A really simple expansion of this idea of helping out with defining what function is the main function, is to pass in &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;sys.argv&lt;/span&gt; and to return a value to signify exit status: &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;sys.exit(func(sys.argv[1:]))&lt;/span&gt;. So now you have made the decorator more useful than replacing the old __name__ idiom.&lt;br /&gt;
&lt;br /&gt;
But while that is nice and helps deal with the very common case, I wanted more. Why can't you introspect on the arguments the function takes and use that to automatically generate a command-line parser? I did a search and the best I could find is &lt;a href="http://pypi.python.org/pypi/entrypoint"&gt;entrypoint&lt;/a&gt;, but it doesn't go far enough for me. What I want is to use the full expressiveness of function parameters in Python to express as much about what should/could be given on the command-line along with passing in as little as possible to the decorator in order to replicate the common case of command-line parsing; think just as easy as &lt;a href="http://docs.python.org/py3k/library/getopt.html#module-getopt"&gt;getopt&lt;/a&gt; but more powerful by using as much of &lt;a href="http://docs.python.org/py3k/library/argparse.html#module-argparse"&gt;argparse&lt;/a&gt; as you can without coming up with complicated rules about how things should work (since once you pass a certain complexity threshold you should just build the argument parser using argparse's API directly and stop trying to optimize for it like I'm suggesting).&lt;br /&gt;
&lt;br /&gt;
So what do we have at our disposal to build such a decorator? We have positional arguments so we know how many arguments are required without some specific qualifier. We have variable positional arguments (e.g. &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;*args&lt;/span&gt;) to take an optional number of extra arguments at the end of the command-line. We have keyword arguments which are optional flags that one can specify. You could even have variable keyword arguments for major flexibility, but that just seems like a total lack of structure the CLIs just don't typically provide. With all of that you can reproduce getopt without any issue for long-form names. For short names, I would say you need to pass in a mapping of short names to long names into the decorator. Same goes for long names to help string (you can use the function's docstring for the main help for the app itself).&lt;br /&gt;
&lt;br /&gt;
But where things get really interesting is when you take into consideration function annotations. That opens up the possibility of going beyond getopt and potentially supporting argparse's &lt;a href="http://docs.python.org/py3k/library/argparse.html#action"&gt;action&lt;/a&gt;, &lt;a href="http://docs.python.org/py3k/library/argparse.html#nargs"&gt;nargs&lt;/a&gt;, and &lt;a href="http://docs.python.org/py3k/library/argparse.html#type"&gt;type&lt;/a&gt; options. Take the type option as an example. You could say &lt;span style="background-color: #eeeeee;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;limit:int=10&lt;/span&gt;&lt;/span&gt; to have a command-line option called &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;--limit&lt;/span&gt; which only accepted an integer and defaulted to 10. &amp;nbsp;This obviously could also work with float or any other type where you can just pass in a string to the constructor to get back an instance of the type. So you have a general case which can be useful, but you can you potentially special-case some things to get enhanced functionality where it doesn't make sense to simply take in a string?&lt;br /&gt;
&lt;br /&gt;
Lists pose an interesting option as argparse provides both nargs for specifying the number of arguments to a single option, or the append action for accepting multiple instances of the same option and accumulating them. In my mind both can be expressed in a way that I think makes sense but some might view as too magical. If you specify &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;names:list=[]&lt;/span&gt;, then that supports the append action, e.g. &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;--names Brett --names Andrea&lt;/span&gt; leads to names being set to &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;['Brett', 'Andrea']&lt;/span&gt;. But if you were to do &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;names:['+']=[]&lt;/span&gt;, then that would get the same result from &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;--names Brett Andrea&lt;/span&gt;. In other words, the list type specifies the append action while a list instance specifies using the nargs option with the single item in the list acting as the value to set to nargs.&lt;br /&gt;
&lt;br /&gt;
For booleans, I would want the use of the bool type to mean use either the store_true or store_false action based on what the default argument was. So &lt;span style="background-color: #eeeeee; font-family: 'Courier New', Courier, monospace;"&gt;turn_on:bool=True&lt;/span&gt; would use the store_false action since the argument is meant to be a boolean and it's default value is True, meaning that if the option was specified it represents the reverse.&lt;br /&gt;
&lt;br /&gt;
Finally, the tricky bit is for files since that is a common command-line argument and you might as well open the file and close it for the function. The solution argparse uses is a specific &lt;a href="http://docs.python.org/py3k/library/argparse.html#filetype-objects"&gt;FileType class&lt;/a&gt; where you can pass specific arguments to use when opening the file. The problem is that it doesn't support everything open() does, e.g. encoding. So what I would want to do instead is provide a partial function that took everything &lt;b&gt;but&lt;/b&gt;&amp;nbsp;the file path and then when it came time to call the main function, passed in the file path to the partial function, passed the returned file to &lt;a href="http://docs.python.org/py3k/library/contextlib.html#contextlib.closing"&gt;contextlib.closing()&lt;/a&gt;, and then passed it on to the main function. You could even generalize a lot of this and simply say that whatever is specified as the function annotation, if it isn't a special-case like lists, then you call the annotation with what came from the command-line and if it provides a context manager it is used before calling the main function.&lt;br /&gt;
&lt;br /&gt;
So those are my thoughts on using function parameters as a DSL for getopt++/argparse-- functionality on a Saturday morning. Honestly the most complicated bit would be constructing the arguments to pass to the main function in the right order, otherwise it's just introspecting on a function's parameters and making the proper call to argparse. But then again the real question is whether anyone thinks this at all sounds reasonable enough to code it up.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/GQTu3iJmOAE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/1179193750413927939?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/1179193750413927939?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/GQTu3iJmOAE/thoughts-on-using-function-signatures.html" title="Thoughts on using function signatures as a DSL for CLI parsers" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/05/thoughts-on-using-function-signatures.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0ENQ30_eyp7ImA9WhVWFks.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-8878728228228327079</id><published>2012-04-28T20:21:00.001-07:00</published><updated>2012-04-28T20:21:32.343-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-28T20:21:32.343-07:00</app:edited><title>Playing with the Ninja build system</title><content type="html">Whenever I learn a new programming language I end up writing some&lt;a href="http://code.google.com/p/bcannon/source/browse/#hg%2Flanguages"&gt; toy examples&lt;/a&gt; to try to get a feel for what the language is about. This leads to the need to build code using many different compilers with their own flags, quirks, etc. Up until today I had used SCons for my build setup. But honestly, it always seemed like overkill to me. Because I only had about 5 programs to build per language with at most two files used to produce the program, a full-blown build system was never really needed. Add to the fact that I am building for languages that no build system would have built-in support for, it led me to always have a wandering eye for another build system I could use.&lt;br /&gt;
&lt;br /&gt;
This past week someone on Google+ &amp;nbsp;shared a &lt;a href="https://plus.google.com/108996039294665965197/posts/SfhrFAhRyyd"&gt;post comparing configure+make, cmake+make, and cmake+ninja&lt;/a&gt;. I had never heard of &lt;a href="http://martine.github.com/ninja/"&gt;Ninja&lt;/a&gt;, so I decided to have a look. It turns out someone had written a build tool whose only explicit job was to take a DAG, figure out what needed to be built, and then execute the commands for the build. No crazy metadata checks like Make, or fanciful features, just bare-bones building. Ninja was actually designed to be a target for other higher-level build systems like cmake which can do the pre-computation of what the DAG should be, leaving it to Ninja to drive the needed compilation.&lt;br /&gt;
&lt;br /&gt;
What attracted me to it was that it was fast and the syntax was simple. I have code examples for 16 languages, of which 10 have build rules (one happens to be Python 2.7 as I pre-compile the .pyo files). Turned out to be a pretty straight-forward process to take my custom SCons commands and just translate them to the subsequent shell commands that Ninja would execute for me. They are a tad verbose in order to make sure that the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ninja -t clean &lt;/span&gt;&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;command would clean up all intermediary files (I'm looking at you OCaml, Haskell, Java, and Scala). But as I said, I typically never have more than 5 programs to build per language, so it wasn't that much of a burden. And if I really cared I could have written a Python script to auto-generate the Ninja files for me, but I decided the effort of writing the code would be just as much as writing the build files by hand.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;I realize I could have used Make, but I honestly am not&amp;nbsp;enamoured&amp;nbsp;with that tool; requiring tabs just rubs me the wrong way. Plus it's rather slow in the common case of only changing a file or two compared to a complete build from scratch.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;Overall, for my weird case Ninja worked out. For something more complex, though, I will consider looking at cmake+ninja as a build solution.&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/bkE9DKXsA6Q" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8878728228228327079?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8878728228228327079?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/bkE9DKXsA6Q/playing-with-ninja-build-system.html" title="Playing with the Ninja build system" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/04/playing-with-ninja-build-system.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYBRHsyeip7ImA9WhRaEks.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-277617608959410728</id><published>2012-02-14T15:29:00.001-08:00</published><updated>2012-02-14T15:29:15.592-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-14T15:29:15.592-08:00</app:edited><title>The re-launch of py3ksupport!</title><content type="html">The reason the past few blog posts I have written have been App Engine-themed is because I have re-launched&amp;nbsp;&lt;a href="http://py3ksupport.appspot.com/"&gt;py3ksupport&lt;/a&gt;! I did a complete rewrite of the code to make it more efficient (since I'm paying $9/month for the site) and at the same time moved over to HRD so as to guarantee the site is always up.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Before I discuss some unique features of py3ksupport, I want to point out that right now that 56 - 60% of the top 50 projects based on downloads of their latest PyPI release support Python 3. The reason for the range is that some projects had in-development support last time I looked and since that can change underneath me I wanted to cover the possibility the data was stale. But the key point is that 8 of the top 10 projects support Python 3 and one of them has support under development along with over half of the top 50 projects.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So I'm sure the site explains itself (and the&amp;nbsp;&lt;a href="http://py3ksupport.appspot.com/faq"&gt;FAQ&lt;/a&gt;&amp;nbsp;fills in gaps), but I figured I should explain some of the more unique features of the site. One is the&amp;nbsp;&lt;a href="http://py3ksupport.appspot.com/faq#metadata_definition"&gt;metadata rating&lt;/a&gt;&amp;nbsp;given to each project. Basically I wanted to shame project owners into updating their project metadata. LOTS of projects don't bother to specify the Python support metadata for their projects which makes my life difficult and is unfortunate for users. For instance, of projects bothered to specify the exact versions of Python they support then users could easily tell from the&amp;nbsp;&lt;a href="http://cheeseshop.python.org/"&gt;Cheeseshop (nee PyPI)&lt;/a&gt;&amp;nbsp;whether they could use the project based on what version of Python they are tied to. I might have to do some public shaming at PyCon if the situation doesn't improve. =)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The other key point is that I personally keep the front page up to date. If a new project shows up on the front page that does not have the proper metadata specified then I personally search online to find out the status of the Python 3 support. Since I get emailed each day when this happens the situation tends to get fixed that day and will be noticed within an hour of me fixing it (the length of time I have things cached).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I'm hoping to eventually move to measuring an project's popularity based on the download rate for the lifetime of the application (instead of just the latest release) to give a more accurate reflection of how popular a project is.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/fgA2iNupAXU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/277617608959410728?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/277617608959410728?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/fgA2iNupAXU/re-launch-of-py3ksupport.html" title="The re-launch of py3ksupport!" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/02/re-launch-of-py3ksupport.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MMQ3o5fCp7ImA9WhRbFUo.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-8633124756751933901</id><published>2012-02-06T16:44:00.000-08:00</published><updated>2012-02-06T16:44:42.424-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-06T16:44:42.424-08:00</app:edited><title>How I bootstrapped importlib</title><content type="html">If you have been reading this blog over the past five years I am sure you have read a &lt;a href="http://sayspy.blogspot.com/2007/06/what-i-have-and-will-be-up-to.html"&gt;&lt;span id="goog_524969007"&gt;&lt;/span&gt;post&lt;span id="goog_524969008"&gt;&lt;/span&gt;&lt;/a&gt; or five about my desire to &lt;a href="http://sayspy.blogspot.com/search?q=bootstrap+importlib"&gt;bootstrap importlib&lt;/a&gt;&amp;nbsp;into Python as &lt;a href="http://bugs.python.org/issue2377"&gt;&lt;b&gt;the&lt;/b&gt;&amp;nbsp;implementation of _&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;_import__&lt;/span&gt;&lt;/a&gt;. Well, as of today I'm willing to say that the difficult technological hurdles have been scaled! At this point the only thing holding me back from taking my code from &lt;a href="https://hg.python.org/sandbox/bcannon#bootstrap_importlib"&gt;https://hg.python.org/sandbox/bcannon#bootstrap_importlib&lt;/a&gt; and making importlib drive import statements are some small compatibility issues, integrating into the build process better, a code review, and python-dev sign-off. In other words all of the interesting problems have been solved, so I'm finally ready to write a blog post discussing how I pulled off what I have.&lt;br /&gt;
&lt;br /&gt;
So how exactly do you import &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;__import__&lt;/span&gt;? To begin, as with any bootstrap challenge, you need to figure out what is available to you so you know what your design parameters are. In my case I knew I couldn't import anything that required filesystem access since half of import is handling the search for a module (the other half is the actual importing); if I wanted to import a file I would need to essentially write half of import in C to work properly. This restriction also has unexpected side-effects, e.g. you can't rely on open() because that is part of the io module which is a Python module.&lt;br /&gt;
&lt;br /&gt;
That meant I could only rely on built-in modules. If you run &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;sys.builtin_module_names&lt;/span&gt; you will discover what is available directly within the CPython binary. The question then becomes if that is enough? It turns out that yes, those built-in modules are enough to perform an import. OK, so you know you have the bare minimum modules required to do an import, but how the heck do you get the built-in modules into the global scope of the module that imports module since you can't use an import statements?&lt;br /&gt;
&lt;br /&gt;
This is when Python's dynamism comes in handy. Since the import statement doesn't do much more than pull in the module object and assign it to a variable at the global scope of the module, I just needed to get the module object for importlib and assign to its __dict__ the built-in modules I needed. Turns out that sys and imp are enough to allow importlib to handle the import of the rest of the built-in modules needed for import to work, so that kept this bit of code short.&lt;br /&gt;
&lt;br /&gt;
But this brings up the next quandry: how do I create a module object of importlib? If I end up searching for importlib on sys.modules then I would have ended up implementing a decent chunk of import itself. So how could I get the module object? This is when frozen modules comes into play.&lt;br /&gt;
&lt;br /&gt;
A frozen module is just a C array containing the marshaled code for a module (which is what a .pyc file is sans magic number, timestamp, and now file size of the source). Since marshal is a built-in module then frozen modules can be loaded without issue. That means you can load a frozen module without using import (much like importing built-in modules).&lt;br /&gt;
&lt;br /&gt;
And that is all of the parts needed to import importlib w/o import. =) To summarize, you get importlib set as __import__ by doing the following:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Import the frozen module (i.e. read in a C array of a marshaled module object and unmarshal it)&lt;/li&gt;
&lt;li&gt;Import sys and imp (built-in modules, so done in C code by calling key C functions which return module objects) and set it on the module object&lt;/li&gt;
&lt;li&gt;Call Python code to import the rest of the built-in modules using sys and imp&lt;/li&gt;
&lt;li&gt;Set Python-based __import__ on the builtins module&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
And voila! __import__ ends up implemented in pure Python code. Now I just need to clean up the code, fix the compatibility issues, rip out the old C code, and get python-dev to sign off. =) Hopefully I will get far enough I will have a lightning talk at PyCon with benchmark numbers to show this is actually all a good thing (including ripping out a ton of C code, especially if I can re-implement chunks of imp in pure Python =).&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/mv3y9TN02TY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8633124756751933901?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8633124756751933901?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/mv3y9TN02TY/how-i-bootstrapped-importlib.html" title="How I bootstrapped importlib" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/02/how-i-bootstrapped-importlib.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAFR3kyfCp7ImA9WhRUFk0.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-7049292135010812002</id><published>2012-01-26T09:58:00.002-08:00</published><updated>2012-01-26T09:58:36.794-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-26T09:58:36.794-08:00</app:edited><title>Asynchronous XML-RPC in Python</title><content type="html">Do you use XML-RPC (and specifically the &lt;a href="http://docs.python.org/library/xmlrpclib.html#module-xmlrpclib"&gt;xmlrpclib&lt;/a&gt;/&lt;a href="http://docs.python.org/py3k/library/xmlrpc.client.html"&gt;xmlrpc.client&lt;/a&gt; from Python's stdlib)? Do you like &lt;a href="http://docs.python.org/py3k/library/xmlrpc.client.html#multicall-objects"&gt;multi-calls&lt;/a&gt;? Wish you could construct your XML-RPC multi-calls in a way so that you could make them asynchronous by constructing the call from scratch? Then you're in luck because I already did the hard work of figuring out the details for you! =)&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;In my case I needed to communicate with an XML-RPC server that supported multi-calls, but in an asynchronous fashion with a non-standard communication object (i.e. not sockets but App Engine's urlfetch). So I had to piece together how to make a XML-RPC client call that used multi-calls so that I could do it asynchronously myself.&lt;br /&gt;
&lt;br /&gt;
The first thing to know is that a multi-call is a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;system.multicall&lt;/span&gt; function call to the server. It takes a sequence of arguments that specify what each individual function call should be. Each sequence item contains a dict with two keys: &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;"methodName"&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;"params"&lt;/span&gt;. The "methodName" key has a string value of the function name to call on the XML-RPC server. The "params" key holds the tuple of arguments (and it must be the tuple type and you must use a tuple even if it is just a single argument --think of what it would take for the call to work with *args) to pass to the function named in "methodName".&lt;br /&gt;
&lt;br /&gt;
Knowing what function you are calling on the other end (system.multicall) and having a sequence of dicts specifying what you are calling in hand, you can make your call to the server. First you need to encode everything into XML:&amp;nbsp;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;a href="http://docs.python.org/py3k/library/xmlrpc.client.html#xmlrpc.client.dumps"&gt;xmlrpc.client.dumps&lt;/a&gt;((seq_of_args,), 'system.multicall')&lt;/span&gt; (notice how I passed the sequence of dicts in a tuple -- and I mean a tuple, not a list). With the XML now in hand, you make the actual call to the server by making a POST with the XML as the body and set the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Content-Type&lt;/span&gt; header to &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;text/xml &lt;/span&gt;&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;using whatever asynchronous mechanism you want to use to make the call.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
What you get back from the server is XML that you can load with &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;a href="http://docs.python.org/py3k/library/xmlrpc.client.html#xmlrpc.client.loads"&gt;xmlrpc.client.loads&lt;/a&gt;(data, use_datetime=True)(c&lt;/span&gt;hances are you will want the [0][0] value as that contains a sequence of results from each function call you requested). Do realize, though, that there is no indication of what function returned what, so you will need to correlate the index of the return value with what call you made (&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;zip()&lt;/span&gt; makes this trivial).&lt;br /&gt;
&lt;br /&gt;
And that's how you construct an XML-RPC multi-call from scratch in Python so you can make an asynchronous call. If you want to see an example of all this, see &lt;a href="http://code.google.com/p/bcannon/source/browse/sites/py3ksupport-hrd/queue.py#47"&gt;this code&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/fUpp6oimx78" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/7049292135010812002?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/7049292135010812002?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/fUpp6oimx78/asynchronous-xml-rpc-in-python.html" title="Asynchronous XML-RPC in Python" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/01/asynchronous-xml-rpc-in-python.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcFSHc5eip7ImA9WhRUFkU.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-45319338764901705</id><published>2012-01-24T15:44:00.000-08:00</published><updated>2012-01-27T09:06:59.922-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-27T09:06:59.922-08:00</app:edited><title>Grab bag of tips when working with App Engine unit testing</title><content type="html">[update: App Engine doc bug is being fixed and should be publicly visible in 1.6.2 or 1.6.3]&lt;br /&gt;
&lt;br /&gt;
First, an announcement:&amp;nbsp;&lt;a href="https://us.pycon.org/2012/registration/"&gt;register for PyCon&lt;/a&gt;! It's a great conference and tons of fun. Early bird ends on the 25th.&lt;br /&gt;
&lt;br /&gt;
With that out of the way, this blog post is going to be testing an App Engine app. This can be, liking testing any complex system, is painful. And unfortunately the documentation on this subject is somewhat lacking for App Engine. But hopefully this post about random things to be aware of when writing unit tests for App Engine can help prevent someone else from having to learn the hard way like I did.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;First thing you should do when testing an App Engine app is set up a &lt;a href="http://code.google.com/appengine/docs/python/tools/localunittesting.html"&gt;testbed&lt;/a&gt;. This will allow you to stub out various parts of App Engine so your tests run in isolation without having stale state carrying over. You basically create a testbed which holds state. You then activate the system by setting some core environment variables with defaults. After that you do your own tweaks to env vars. From there you activate various stubs. And then finally you deactivate the whole thing to clean up...&lt;br /&gt;
&lt;br /&gt;
But you need to realize there is an apparent&amp;nbsp;&lt;a href="http://code.google.com/p/googleappengine/issues/detail?id=4950"&gt;error in the docs&lt;/a&gt;&amp;nbsp;(which will be fixed no later than 1.6.3, possibly 1.6.2). The stated order of calling &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;activate()&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;setup_env()&lt;/span&gt; are wrong; you should call &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;activate(&lt;/span&gt;) before calling &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;setup_env()&lt;/span&gt; in order to set the default env vars before you begin to set your own.&lt;br /&gt;
&lt;br /&gt;
Another thing you should know about is that &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;setup_env()&lt;/span&gt; has an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;overwrite&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;argument. This tells the method to overwrite any pre-existing env var; otherwise the call will skip changing any pre-existing env vars. This can call issues if your app presets some env vars that should be overridden during testing. I would honestly consider using that argument every time to make sure things work the way you expect.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;And the last tip specific to &lt;/span&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;setup_env()&lt;/span&gt;&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;is&amp;nbsp;make sure to pass &lt;b&gt;all&lt;/b&gt;&amp;nbsp;of your env var changes in a single call. Otherwise you can end up with some settings be changed as they have a default value.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
In relation to handling users, to specify who the logged in user is you should set the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;USER_EMAIL&lt;/span&gt; env var. That will cause App Engine to return a user with the specified email address when calling &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;users.get_current_user()&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
Random thing about email testing is that &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;mail.send_mail_to_admins()&lt;/span&gt; does not write to the mail stub to verify any email was sent. This is because while testing there is no way to specify who admins are, so there is no way to know who to say the emails are sent to. So in order to test the function you will need to mock out the call yourself (personally I'm a fan of &lt;a href="http://pypi.python.org/pypi/mock"&gt;mock&lt;/a&gt; if you don't already have a preferred mocking library).&lt;br /&gt;
&lt;br /&gt;
And finally, you can mock our the request and response objects for a handler. You can call a handler's &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;initialize()&lt;/span&gt; method with the object to use -- for the request and response, respectively -- which allows you to mock and test how the handler does things.&lt;br /&gt;
&lt;br /&gt;
Bonus for those of you using the&amp;nbsp;&lt;a href="http://code.google.com/appengine/docs/python/python27/"&gt;Python 2.7 runtime&lt;/a&gt;:&amp;nbsp;I would consider using unittest's discovery features to drive your unit tests. You can start from &lt;a href="http://code.google.com/p/bcannon/source/browse/sites/py3ksupport-hrd/run_tests.py"&gt;my driver code&lt;/a&gt; and add what you need. But it's nice to just be able to plop down a new test module and have it automatically picked up.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/hgd3z5Wsyxo" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/45319338764901705?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/45319338764901705?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/hgd3z5Wsyxo/grab-bag-of-tips-when-working-with-app.html" title="Grab bag of tips when working with App Engine unit testing" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/01/grab-bag-of-tips-when-working-with-app.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQMSX47fip7ImA9WhRVGEk.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-8061719703454197921</id><published>2012-01-17T15:53:00.000-08:00</published><updated>2012-01-17T15:53:08.006-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-17T15:53:08.006-08:00</app:edited><title>Working with App Engine backends</title><content type="html">This post is all about &lt;a href="http://code.google.com/appengine/docs/python/backends/"&gt;backends in App Engine&lt;/a&gt;, but first I want to make two personal points.&lt;br /&gt;
&lt;br /&gt;
One is that I'm sorry I have not been updating this blog (or really contributing to Python and its great community) more this past year. It was a rather insane 2011 for me personally: I finished my Ph.D., got married, moved to SF&amp;nbsp;&amp;nbsp;(w/o my wife thanks to immigration), started working at Google full-time, moved to Toronto (yes, I moved internationally within the span of 6 months), transferred to the Google Waterloo office and started on a new team. In other words I have been stressed out and busy and busy continuously for what feels like ages. But now that I am back with my wife and I am done with the crazy international moving I don't expect 2012 to be anywhere near as nuts (nor any other year in the near future for that matter if I can help it).&lt;br /&gt;
&lt;br /&gt;
Two, I am no longer on the App Engine team, so all that I am about to say (and will also say in the future as I have a couple of posts to write on App Engine) is from me as just another person using the service. I have been working on a redesign of a website of mine in my spare time and these next couple of posts are based on that work (if you following &lt;a href="https://plus.google.com/115362263245161504841/posts/"&gt;me on Google+&lt;/a&gt; you know what it is, but I'm not ready for a full-blown Internet debut so I'm not going to link here yet). I don't have any insider knowledge here nor speak for the team.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;With all of that out of the way, let's talk about backends! First you need to understand what an &lt;i&gt;instance&lt;/i&gt;&amp;nbsp;is to App Engine. When you hit a website hosted on App Engine, an instance is what is serving that request. Now an App Engine app can have anywhere from 0 to thousands of instances up and running at any one time to handle traffic. So think of an instance as a copy of your app that is running on App Engine serving traffic.&lt;br /&gt;
&lt;br /&gt;
Normally you have some time restrictions on how long any of your instances can take to service a request. If it is an HTTP request from the general Internet you have 60 seconds. If it is from a &lt;a href="http://code.google.com/appengine/docs/python/config/cron.html"&gt;cron job&lt;/a&gt; or &lt;a href="http://code.google.com/appengine/docs/python/taskqueue/overview-push.html"&gt;push queue&lt;/a&gt;&amp;nbsp;(i.e. from within your own app) you have 10 minutes. Now both time restrictions are actually rather long and you can accomplish a lot within those restrictions. And in the case of push queues, you can break your work up into multiple tasks so that you really can take as much time as you need as long as you can slice your work into 10 minute time chunks.&lt;br /&gt;
&lt;br /&gt;
But there are just those times when you want something that will take more than 10 minutes, such as a process that is constantly polling some other service to get data. In those instances you want a backend since they are instances that run for as long as you want (assuming App Engine doesn't kill it for misbehaving or some other sysadmin reason). You can have a &lt;i&gt;resident&lt;/i&gt;&amp;nbsp;backend which never stops running or a &lt;i&gt;dynamic&lt;/i&gt;&amp;nbsp;backend that will stop running when it is done executing, but either type can take about 24 hours to run if it wants.&lt;br /&gt;
&lt;br /&gt;
The way you use instances is to send requests to the backend's subdomain. You name your backends in your backend.yaml file which becomes the subdomain off of your appspot.com subdomain for addressing your backend. So, assuming you have a backend name "forever" for an app named "spam", the domain for the instance will be forever.spam.appspot.com. &amp;nbsp;You can then create URL handlers in your instance and hit those URLs to cause your instance to do it's long-running thing.&lt;br /&gt;
&lt;br /&gt;
Now for those of you who have been using App Engine for a while you might notice that the subdomain for a backend looks just like the specific version ID URL for your app, and that's on purpose. Thanks to it having the same format you can specify a backend name anywhere you can specify a version ID for your app and have it use your backend. E.g. to have a cron job that hits your backend you specify your backend's name as the "version" of your app to hit&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;&amp;nbsp;in your cron.yaml.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Times, 'Times New Roman', serif;"&gt;And before anyone worries, your backend defaults to being private to your app. If you really want your backend reachable from outside of your app (i.e. the public) you can specify that in your backend.yaml.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
While backends sound fantastic and address an old complaint against App Engine and its lack of background processes, I have two warnings/tips about using them.&lt;br /&gt;
&lt;br /&gt;
First, the tip: you can't use the OS X AppEngineLauncher to use backends. When you launch a dev_appserver you need to specify the --backends flag. You can do that manually in the AppEngineLauncher, but you need the flag for appcfg.py as well which you can't specify. So if you want to use backends (and thus want to specify the --backends flag) you will need to use the command-line version of the tools. Obviously this is a minor thing, but it took me quite a while to realize that was why backends were not working for me.&lt;br /&gt;
&lt;br /&gt;
And my warning is that don't expect to use backends on the free quota. While you get 9 free hours of backend usage, you can blow through that surprisingly quickly. But the real issue is all of the other quotas that you have on App Engine. For instance, I was hitting another server to get data to process. What ended up happening is that I was maxing our my incoming bandwidth quota for urlfetch. So then I started to write code to throttle my requests. But even then I occasionally hit the quota. To properly handle that I would need to grab the quota exception and then retry or heavily throttle myself so that I never hit the issue. At that point I was writing code to throttle my requests and to retry when I managed to request to quickly; that's just silly when I have push queues to do that for me automatically. So I personally ended up not using backends in my case (although ironically after I refactored the code I started hitting another free quota limit which led to me turning on billing, so now I'm using $0.05/day in quota, so the app is just costing me $9/month).&lt;br /&gt;
&lt;br /&gt;
But when you are willing to pay for backends they are great for what they provide, but you just have to realize they are just another tool and are not always going to be the best solution for everything (especially if you don't want to pay to use App Engine).&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/vlDFTMbfl64" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8061719703454197921?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8061719703454197921?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/vlDFTMbfl64/working-with-app-engine-backends.html" title="Working with App Engine backends" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2012/01/working-with-app-engine-backends.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQASX0ycCp7ImA9WhdWGEg.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-3205824887431592899</id><published>2011-09-12T11:32:00.002-07:00</published><updated>2011-09-12T11:32:28.398-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-12T11:32:28.398-07:00</app:edited><title>PyCon 2012 CFP ends in a month!</title><content type="html">The title says it all: the CFP for PyCon 2012 ends in a month, so you should seriously start thinking about getting those proposals in! As I say every year, you do not need to be a Python celebrity or &amp;nbsp;have presented previously in order to get a talk accepted. Having been on the PC from the beginning of PyCon I can tell you that we very happily give slots to people we have never heard of. As long as your proposal shows you are organized and your topic is interesting your talk will be &amp;nbsp;given a serious chance for acceptance.&lt;br /&gt;
&lt;br /&gt;
And sorry about the lack of posts. My Python free time is limited at the moment as most free time is spent talking with my wife over a G+ Hangout thanks to US immigration perpetually dragging their feet, keeping her in Toronto and me in SF and causing general misery spread across the continent. That means what little time I do have I spend on trying to get importlib bootstrapped (which you can follow in my&lt;a href="http://hg.python.org/sandbox/bcannon/shortlog/6022795c90d4"&gt; sandbox/bcannon repo in the bootstrap_importlib branch&lt;/a&gt;) instead of blogging. But once the bootstrapping is done (or I come up with some rather clever thing) I will do a technical post.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/6kjWKEPFAQo" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3205824887431592899?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3205824887431592899?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/6kjWKEPFAQo/pycon-2012-cfp-ends-in-month.html" title="PyCon 2012 CFP ends in a month!" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/09/pycon-2012-cfp-ends-in-month.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQFRng9eSp7ImA9WhdTGEg.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-395568833907615931</id><published>2011-07-16T15:11:00.001-07:00</published><updated>2011-07-16T15:11:57.661-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-16T15:11:57.661-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>How to import a module from just a file path</title><content type="html">&lt;a href="http://ivory.idyll.org/blog"&gt;Dr. Brown&lt;/a&gt; &lt;a href="http://twitter.com/#!/ctitusbrown/status/91712212208599040"&gt;asked on Twitter&lt;/a&gt; whether there was a single expression (e.g., no semi-colons or abuses of &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;and&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;or &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;or&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;) that could import a module from a file path, either through a stdlib function call or just constructed from scratch; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;mod = import_from_path('some_file.txt')&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;. Because it involved import, I got cc'ed on the tweet while various people tried to come up with a solution. In the end people realized that it's not possible in Python 2 (but it is in Python 3). But how hard could it be, right? Right?!?&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;Well, the devil is always in the details. While there are some functions in the stdlib that come close (e.g., execfile() and runpy.run_path()), none of them return the module, but the globals dict. Other people tried to come up with something using 'exec', but it doesn't return anything (in Python 2) so you have to assign what you planned to use as the module ahead of time (that's two lines total if you weren't counting along).&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;In Python 3, though, this is all totally doable thanks to 'exec' becoming a function instead of a keyword:&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Times, 'Times New Roman', serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre&gt;mod = exec(open('path', 'r').read(), __import__('sys').modules.setdefault('name', __import__('imp').new_module(name)).__dict__)
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
This is obviously a complete hack and not something you should use in the real world. But it is a single expression (meeting Titus' restriction) and it even puts the module into sys.modules so that future imports will not have to re-import the module. This hack, though, does assume that you are only importing modules and never packages.&lt;br /&gt;
&lt;br /&gt;
So what would it take to do a proper function that took (at least) a file path and ended up importing that file? First thing is whether you wanted any arbitrary path to be used, or only something for properly named Python modules (e.g., ending in .py, packages being named __init__.py). If you go with the former you need to specify the module name and whether it is a package (and if it is what the value of __path__ should be), else you can just gleam all of that info from the path itself.&lt;br /&gt;
&lt;br /&gt;
After that the next step is to create the module object and populate it. The bare bones thing to do is create the object and specify the __name__ and __file__ attributes, along with __path__ if it applies. This has to be done as a module might do something with those values as a side-effect of importation (and remember folks, never launch a thread as a side-effect of an import! Deadlock awaits those who don't heed that warning).&lt;br /&gt;
&lt;br /&gt;
Third, you create the code object. Now you could technically just read the file and pass it to 'exec', but that won't set up the file path, etc. in the code object for easier traceback issues that may arise when you do the actual executing of the module code.&lt;br /&gt;
&lt;br /&gt;
Fourth, you actually execute the module code and finish initializing your module.&lt;br /&gt;
&lt;br /&gt;
Now all of this ignores storing the module in sys.modules or even checking if it even exists in there. It also doesn't add the module to sys.modules so that future imports can use the module instead of having to do the same thing again. But if you are honestly wanting to import a module by specifying a path, you probably don't care about any of this anyway. And because you ignore sys.modules, you get to ignore the import lock.&lt;br /&gt;
&lt;br /&gt;
So, taking all of this together, here is a basically untested function that does what Titus basically wanted (works in Python 3, but changing it for Python 2 is literally just using the 'exec' statement instead of function):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;import imp

# Step 1
def import_from_path(path, name='&lt;unknown&gt;', package_path=None):
    """Import a module from a specified file path.

    If the module is a package, set package_path to a list of directories that
    is to become __path__.

    """
    # Step 2
    mod = imp.new_module(name)
    mod.__file__ = path
    if package_path is not None:
        mod.__path__ = package_path
    # Step 3
    with open(path, 'r') as file:
        code = compile(file.read(), path, 'exec', dont_inherit=True)
    # Step 4
    exec(code, mod.__dict__)
    return mod
&lt;/unknown&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/ZQL6ixzEXUA" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/395568833907615931?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/395568833907615931?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/ZQL6ixzEXUA/how-to-import-module-from-just-file.html" title="How to import a module from just a file path" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/07/how-to-import-module-from-just-file.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcMR3Y7eSp7ImA9WhZaE08.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-2598909673565259431</id><published>2011-06-28T21:34:00.000-07:00</published><updated>2011-06-28T21:34:46.801-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-28T21:34:46.801-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>My personal plans for Python 3.3</title><content type="html">Now that my life has hit another purgatory moment (waiting to here when my wife's permanent residency interview will be and still in the ramp-up period at work), I have had some time to think about what my personal goals will be for &lt;a href="http://python.org/dev/peps/pep-0398/"&gt;Python 3.3&lt;/a&gt;. This list is in no particular order and I make no promises to actually do any of it as I only have roughly 249 days until alpha1. =)&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;First, I want to &lt;a href="http://bugs.python.org/issue2377"&gt;bootstrap in importlib as the implementation of __import__&lt;/a&gt;. I think I can simply freeze importlib._bootstrap, do some imports of built-in modules, and then have it &lt;i&gt;almost&lt;/i&gt;&amp;nbsp;work. The reason it is "almost" is that importlib relies on _io, which itself relies on importing the os module. That's a problem when you are trying to essentially import what will act as import. I need to have a look still at the _io code to see if the importing of os can be postponed until after importlib is up and running.&lt;br /&gt;
&lt;br /&gt;
Second, I need to finish &lt;a href="http://python.org/dev/peps/pep-0399/"&gt;PEP 399&lt;/a&gt;. Before the whole work/immigration whirlwind started I submitted this PEP to python-dev and got a bunch of feedback on it. The usual push-and-shove led to what seemed to be a general consensus of what the PEP should be striving for, so I think I can wrap it up and get it accepted once I have time to incorporate the feedback (mainly watering down the wording so it is less technical).&lt;br /&gt;
&lt;br /&gt;
Third, I should try to finally get &lt;a href="http://python.org/dev/peps/pep-0362/"&gt;PEP 362&lt;/a&gt; accepted (&lt;a href="http://bugs.python.org/issue8916"&gt;tracking bug&lt;/a&gt;). The code has been up on the Cheeseshop as &lt;a href="http://pypi.python.org/pypi/pep362"&gt;pep362&lt;/a&gt; for &amp;nbsp;over 4 years now without any complaints. Since I know there are users out there (&lt;a href="http://www.voidspace.org.uk/"&gt;Michael Foord&lt;/a&gt; keeps asking me to finally get the code into the stdlib) I figure the API is generally acceptable and there are no secret bugs creeping in there. Basically I just need to rip out the silly use of inspect that is left since I dropped Python 2 support in the development version, make sure I have proper code coverage, and write docs.&lt;br /&gt;
&lt;br /&gt;
Fourth, I need to get an Amazon or Rackspace instance up that generates a coverage report for the stdlib on some reasonable schedule. This first requires me to finally &lt;a href="http://bugs.python.org/issue11561"&gt;review and commit Brandon Rhodes' script &lt;/a&gt;which gets coverage reporting much earlier in the interpreter startup than it does by default. Once that is done I need to get a VM going somewhere that can freshly check out Python, coverage.py, run the test suite under coverage, and then make the coverage report available for viewing. This will make the test coverage not only more visible, but easier for people to help &lt;a href="http://docs.python.org/devguide/coverage.html"&gt;increase it as a starter project&lt;/a&gt; when contributing to Python.&lt;br /&gt;
&lt;br /&gt;
So that is everything I am hoping to do before March 3, 2012. I plan on making the coverage and importlib bootstrapping my priorities, although I will finish PEP 399 first since I hate leaving open PEPs lying about. And I am definitely going to try to not take on any more Python projects until I get through this list as this is already plenty for me to do. =)&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/E6lXuOdUmPE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/2598909673565259431?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/2598909673565259431?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/E6lXuOdUmPE/my-personal-plans-for-python-33.html" title="My personal plans for Python 3.3" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/06/my-personal-plans-for-python-33.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIFSXg6fCp7ImA9WhZQFUw.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-5768404123373137545</id><published>2011-04-22T15:15:00.000-07:00</published><updated>2011-04-22T15:15:18.614-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-22T15:15:18.614-07:00</app:edited><title>Framerates for movies and the debacle that they are</title><content type="html">One of my great weak points is technology, especially those involving movies. While I wouldn't go as far as calling myself a cinephile (e.g., I don't know every random fact about my favorite movies), I do love watching films which means I like trying to make my viewing experience at home rather nice (which honestly has not been that great thanks to my long-lasting student budget).&lt;br /&gt;
&lt;br /&gt;
One of the latest things being debated about the quality of cinema is the &lt;a href="http://en.wikipedia.org/wiki/Frame_rate"&gt;frame rate&lt;/a&gt; of films. Currently movies project at 24 fps. &lt;a href="http://en.wikipedia.org/wiki/ATSC_Standards"&gt;ATSC&lt;/a&gt; (digital broadcasting version of NTSC) is typically 30 fps at 1080p although it can also do 24 fps and the funky rates film and old NTSC video show at (PAL is 25 fps but I'm North American, so I am going to stick with what I know in this blog post). &lt;a href="http://en.wikipedia.org/wiki/Blu-ray_Disc"&gt;Blu-ray&lt;/a&gt; can do 24 fps at 1080p. So everything these days can handle the native projection rate of 24 fps of 35 mm film.&lt;br /&gt;
&lt;br /&gt;
But really, 24 fps?!? Any hardcore gamer is going to tell you that frame rate is unacceptable. You want at least 30, if not 60 fps. As it turns out, so do people watching movies. This is why most decent TVs these days at least output 120Hz video which helps to artificially raise the frame rate and lead to a smoother picture, no matter if the original material is 24 or 30 fps (or even 60, but that is typically reserved for video game output). And even newer TVs can do 240Hz, which leads to an even smoother experience (supposedly; have not experienced it myself).&lt;br /&gt;
&lt;br /&gt;
But what about in the theater? Everything is still filmed and made for 24 fps and that is what projectors (digital and analog) use. Well, two of the more cutting edge directors currently working want to change this. James Cameron has talked about &lt;a href="http://www.engadget.com/2011/04/02/james-cameron-ponders-48-or-60fps-shooting-of-future-avatar-film/"&gt;filming Avatar 2 &amp;amp; 3 at 48 or 60 fps&lt;/a&gt;. Peter Jackson has gone beyond saying and is actually &lt;i&gt;doing&lt;/i&gt; by &lt;a href="http://insidemovies.ew.com/2011/04/12/the-hobbit-48-frames-peter-jackson/"&gt;filming the Hobbit at 48 fps&lt;/a&gt;. According to Jackson the higher frame rate not only looks better, but it makes 3D something that is actually bearable to watch (i.e., the nasty flicker goes away). And it turns out most digital projectors can have their firmware upgraded to project films that use these higher frame rates. And with 48 fps being a multiple of 24, these directors could easily film at 48 fps and make 35 mm prints where every other frame is dropped so old projectors can still show at 24 fps.&lt;br /&gt;
&lt;br /&gt;
But what about watching at home? While it's great that seeing those select films I &lt;i&gt;want&lt;/i&gt; to see in the theaters will be projected at a higher frame rate (e.g., the Hobbit), what about when I want to watch at home? This is where that 48 fps gets sticky. Both blu-ray and ATSC do not support 48 fps at any resolution. Both do, however, support 60 fps at 720p. And I am willing to bet that Netflix streaming won't handle either 48 or 60 fps until we all have fiber connections. Another issue for the 48 fps is that it is not a common divisor of 120 (Hz), making it potentially nasty to artificially raise the frame rate; luckily 48 is a divisor for 240 (Hz).&lt;br /&gt;
&lt;br /&gt;
So the question becomes, how does Hollywood decide to handle this theater/home frame rate discrepancy that is coming our way? Well, with this being Hollywood, I am willing to bet they do it in the way that screws over the home user the most, forcing you to go to the theater for the best experience. That would support the idea of going with 48 fps in theater projection. That way they still get a higher frame rate that helps out 3D projection, they can easily cut 24 fps versions for 35 mm prints, &lt;i&gt;and&lt;/i&gt; they can stick with blu-ray and such at 24 fps as well. All of this while getting to keep a nice hook to get people who care about video quality to come to the theaters to pay for your expensive movie ticket. They can then come out with a new home video standard that supports 48 fps and force us to all buy our movie collections yet again (you know George would be happy to sell you Star Wars for the bazillionth time on a new format, although unless he lets Han shoot first I ain't going for it). If they go 60 fps they can at least do 720p60, but then again do we really want the drop in resolution?&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/slCtNHrAbqc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/5768404123373137545?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/5768404123373137545?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/slCtNHrAbqc/framerates-for-movies-and-debacle-that.html" title="Framerates for movies and the debacle that they are" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/04/framerates-for-movies-and-debacle-that.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4MRnw5fCp7ImA9WhZTGU4.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-6088657966087326699</id><published>2011-03-23T18:43:00.000-07:00</published><updated>2011-03-23T18:43:07.224-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-23T18:43:07.224-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>importlib: doing it, and doing it, and doing it well</title><content type="html">Earlier today I pushed a change to CPython which allows importlib to pass Python's test suite as the implementation of __import__ (sans failures because nothing expects __loader__ to be universally set on modules). This means that there is no known compatibility issues standing between me and making importlib CPython's implementation of __import__.&lt;br /&gt;
&lt;br /&gt;
So what was the final hurdle? It basically boils down to code objects and their immutability. When you import from bytecode you are essentially loading a code object which represents the module (basically using marshal.loads()). The issue is that code objects embed what file they were created from (the co_filename attribute). But what happens if you relocate a .pyc file? Should co_filename point to the place the file was originally created at or at its current location? Turns out Python thinks it should be the latter.&lt;br /&gt;
&lt;br /&gt;
The issue with updating the co_filename attribute on a code object is that it can only be done by C code; attributes on a code object are immutable from Python. My original plan was to modify marshal.loads() to take a filename argument which represented where the marshal data came from. That way marshal could fix co_filename while keeping the attribute immutable. But this didn't work.&lt;br /&gt;
&lt;br /&gt;
It turns out that the attribute used by __import__ for fixing co_filename is not as thorough as the recursive solution I came up with for marshal.loads(). There is a loop that looks for objects to fix, but as soon as one of them is accurate the search is stopped by __import__. Rather than replicate this somewhat odd solution for marshal, I simply exposed a private API in imp for me to use in order to mutate a code object's co_filename attribute. Not an elegant solution, but since I am taking a PyPy view to import (i.e., it's my job to make importlib as compatible as possible and not tweak __import__ to fit my needs) I didn't have much of a choice.&lt;br /&gt;
&lt;br /&gt;
Regardless, it feels very satisfying to have an implementation of import that passes the test suite now. This means I can work towards bootstrapping importlib as the implementation of import. I am planning to go with some bytecode-freezing solution for CPython where there is a build rule which recreates the bytecode any time importlib._bootstrap is mutated. That will remove the worry of having to rely upon some external file for import to work (otherwise I could come up with some import shim that did enough to import importlib directly). And with &lt;a href="https://profiles.google.com/u/0/bcannon/posts/fZGUuvurVGy"&gt;performance of importlib already being acceptable&lt;/a&gt; I feel fairly confident that this bootstrapping will happen in Python 3.3 (I have started work in the bootstrap_importlib branch of my &lt;a href="http://hg.python.org/sandbox/bcannon/"&gt;personal repo&lt;/a&gt;).&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/_19rvqPOWqc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/6088657966087326699?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/6088657966087326699?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/_19rvqPOWqc/importlib-doing-it-and-doing-it-and.html" title="importlib: doing it, and doing it, and doing it well" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/03/importlib-doing-it-and-doing-it-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cFRX0yfyp7ImA9WhZTFks.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-9204404256444674504</id><published>2011-03-20T17:56:00.000-07:00</published><updated>2011-03-20T17:56:54.397-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-20T17:56:54.397-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PyCon 2011 wrap-up</title><content type="html">tl;dr version: it was awesome! Read on to find out what I did at the sprints and two themes that I found at the conference.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;Since I have not had a chance to blog until now, people like &lt;a href="http://www.boredomandlaziness.org/"&gt;Nick Coghlan&lt;/a&gt; and &lt;a href="http://blog.briancurtin.com/"&gt;Brian Curtin&lt;/a&gt; have beaten me to writing good summaries of the VM summit, language summit, conference, and sprints so I won't worry about doing an overall summary of everything.&lt;br /&gt;
&lt;br /&gt;
At the sprints I almost exclusively focused on my &lt;a href="http://py3ksupport.appspot.com/"&gt;Python 3 on PyPI&lt;/a&gt; website. After squashing a bunch of bugs I added two more popularity metrics. The first metric is download rate. This is to help balance out against total download count which favours older projects thanks to simply having been available longer. I also added the poll results as found on the front page of &lt;a href="http://www.python.org/"&gt;www.python.org&lt;/a&gt; (look in the upper-right corner of the page). The download rate has about 50% of those projects converted which is great, while the poll results is at 16% which is also very good considering people are explicitly asking for those projects to be converted because they were not at the time of voting. And because people seem to have some odd desire to see the crap code I wrote for this website, you can find it &lt;a href="http://code.google.com/p/bcannon/source/browse/#hg%2Fsites%2Fpy3ksupport"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
As for the two themes I see gaining more exposure in the upcoming year, one was obviously Python 3 support from projects. There is now a &lt;a href="http://python3porting.com/"&gt;book out by Lennart Regebro&lt;/a&gt; [&lt;a href="http://www.amazon.com/Porting-Python-3-depth-guide/dp/1456411519?ie=UTF8&amp;amp;tag=askewedthoughts&amp;amp;link_code=btl&amp;amp;camp=213689&amp;amp;creative=392969" target="_blank"&gt;Amazon&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=askewedthoughts&amp;amp;l=btl&amp;amp;camp=213689&amp;amp;creative=392969&amp;amp;o=1&amp;amp;a=1456411519" style="border: none !important; margin: 0px !important; padding: 0px !important;" width="1" /&gt;] (which I wrote the foreword for), a good number of projects have already switched, Django will be switching this summer, and at the sprints Jim Fulton started porting &lt;a href="http://svn.zope.org/zc.buildout/branches/python-3-2/"&gt;zc.buildout to Python 3&lt;/a&gt;&amp;nbsp;(which happens to be the largest Python 3 holdout according to my website at the moment). In other words the momentum is there for Python 3 and I continue to not worry about it.&lt;br /&gt;
&lt;br /&gt;
The other theme which gained more traction is separating Python the language from CPython the interpreter. &lt;a href="http://speed.pypy.org/"&gt;PyPy's performance&lt;/a&gt; is now good enough to make it a serious consideration for anyone to use. And once they release a version supporting Python 2.7 (&lt;a href="http://ironpython.net/"&gt;IronPython&lt;/a&gt; beat them to Python 2.7 compatibility) then they will be in a position to become the de-facto interpreter people use when they don't have specific requirements (e.g., embedding Python in a Java program and thus requiring Jython). What this means (at least to me) is that python-dev is going to need to start to shift towards a stance where the Python language takes precedence over CPython the interpreter. While CPython will continue to be the reference implementation (don't ask if PyPy will become it; I don't think they want that responsibility honestly), certain considerations are going to be needed in order to make sure that things we do in the Hg repository do not end up hurting the other VMs.&lt;br /&gt;
&lt;br /&gt;
To help with this goal of making sure the Python language does not play favourites, I am planning on doing three things. One is a PEP I am drafting up dictating that C extension code in the stdlib must be kept fully compatible with any pure Python equivalent code. It will also say that any extension module with no matching pure Python version must get an exemption to be included in the stdlib. This is to prevent all the VMs from having to re-implement every extension module on their own, essentially leading to four versions of the same module.&lt;br /&gt;
&lt;br /&gt;
The second thing is getting importlib to become the de-facto implementation of import in Python. Every single VM hates implementing import. It's subtle and complicated, making it very tough to implement in a way that is conformant. By moving it to pure Python, importlib will allow all of the VMs to simply use importlib and thus not have to re-implement import.&lt;br /&gt;
&lt;br /&gt;
Lastly, a very long-term goal is to break out Python's stdlib into its own repository. This will make it even more obvious that CPython is the reference implementation of Python and that it is not special in any other way. It will also allow the other VMs to use the same code base to prevent duplicated work (the key contributors on the other VMs are already receiving commit privileges on CPython so they can start fixing bugs now). This is a &lt;b&gt;very&lt;/b&gt;&amp;nbsp;long-term project of mine and won't be started until my other two goals mentioned above are finished. In other words my goal is to &lt;i&gt;start&lt;/i&gt;&amp;nbsp;at PyCon 2012 with this.&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/wrgTbuG1Fs4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/9204404256444674504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/9204404256444674504?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/wrgTbuG1Fs4/pycon-2011-wrap-up.html" title="PyCon 2011 wrap-up" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/03/pycon-2011-wrap-up.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQNQng-eip7ImA9Wx9aEko.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-3036978243739097943</id><published>2011-03-04T14:23:00.000-08:00</published><updated>2011-03-04T14:23:13.652-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T14:23:13.652-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Secret site goes live: Python 3 Support on PyPI</title><content type="html">When the &lt;a href="http://python3wos.appspot.com/"&gt;Python 3 Wall of Shame&lt;/a&gt; launched a couple weeks ago, I (along with others) noticed discrepancies (&lt;a href="http://uberpython.wordpress.com/2011/02/12/the-python-3-wall-of-shame/"&gt;discussed in the comments of the announcement blog post&lt;/a&gt;) between the real world and what the list said (e.g., &lt;a href="http://pypi.python.org/pypi/docutils"&gt;doctutils&lt;/a&gt; was listed as not supporting Python 3). A similar issue came from &lt;a href="http://onpython3yet.com/"&gt;On Python 3 Yet?&lt;/a&gt; Both websites seemed to be to accidentally spreading FUD about Python 3 support on PyPI thanks to the projects on PyPI not listing Python 3 support properly. While in no way intentional, it does cause issues when people use these sites as "proof" Python 3 still lacks support from the community.&lt;br /&gt;
&lt;br /&gt;
So how did this happen? Well, projects on &lt;a href="http://pypi.python.org/"&gt;PyPI&lt;/a&gt; are &lt;a href="http://pypi.python.org/pypi?:action=browse&amp;amp;c=533&amp;amp;show=all"&gt;listed as supporting Python 3&lt;/a&gt; when they set the proper Python 3 &lt;a href="http://pypi.python.org/pypi?%3Aaction=list_classifiers"&gt;trove classifier&lt;/a&gt; (&lt;a href="http://docs.python.org/py3k/howto/pyporting.html#universal-bits-of-advice"&gt;instructions on how to fix this&lt;/a&gt; are in the &lt;a href="http://docs.python.org/py3k/howto/pyporting.html"&gt;Python 3 porting HOWTO&lt;/a&gt;). What I suspect has happened is that projects which do support Python 3 but don't have the proper classifier either (a) are not aware they should set it or (b) don't care/too lazy. Either way it leads to a mis-representation of what projects do and do not support Python 3.&lt;br /&gt;
&lt;br /&gt;
To deal with this, I created a website to measure &lt;a href="http://py3ksupport.appspot.com/"&gt;Python 3 support on PyPI&lt;/a&gt;. What differentiates this website from the others is that I am personally curating the list of projects that support Python 3. So while PyPI says docutils does not support Python 3, &lt;a href="http://py3ksupport.appspot.com/pypi/docutils"&gt;my website does&lt;/a&gt;. Same goes for projects which have forks that support Python 3 (e.g., &lt;a href="http://py3ksupport.appspot.com/pypi/setuptools"&gt;setuptools&lt;/a&gt; "supports" Python 3 through &lt;a href="http://py3ksupport.appspot.com/pypi/distribute"&gt;distribute&lt;/a&gt;). I have even begun to flag projects which have working support in their version control system as "maybe" supporting Python 3. I completely understand why the creators of the other websites don't do this; it takes work. But since I have more invested in Python 3 than most people I am willing to put the work in.&lt;br /&gt;
&lt;br /&gt;
If you go to the &lt;a href="http://py3ksupport.appspot.com/"&gt;home page&lt;/a&gt; you will notice that I list a project as either supporting, not supporting, or maybe supporting Python 3. The latter case is there because &lt;b&gt;a ton&lt;/b&gt;&amp;nbsp;of projects do not specify at all if they even support Python 2! My hope is that projects begin to properly set their trove classifiers. This not only benefits the community by letting people know if they do or do not support Python 3, but because it can be used to know how far back they support Python. &amp;nbsp;Take &lt;a href="http://pypi.python.org/pypi/Django/1.2.5"&gt;Django 1.2.5&lt;/a&gt;&amp;nbsp;as an example. It does not have trove classifiers set to let me know that it supports Python 2.4 through Python 2.7. Heck, I don't even know if they have tested against Python 2.7 yet. But if they set their trove classifiers this would be known both visibly and programmatically.&lt;br /&gt;
&lt;br /&gt;
I am asking the community for help combating this problem of projects not listing their Python 3 support properly. If you know of a project which supports Python 3 somehow but that fact is not known on this new website, please either list it over on the &lt;a href="https://convore.com/python/help-me-find-projects-on-pypi-that-support-python-3-but-are-lacking-the-proper-classifier/"&gt;Convore discussion on this topic&lt;/a&gt;, leave a comment here, or leave a comment on Google Buzz along with proof of the Python 3 support (e.g., a link to an official page stating the support). If you tack on a project's PyPI name on to&amp;nbsp;http://py3ksupport.appspot.com/pypi/ (e.g.,&amp;nbsp;&lt;a href="http://py3ksupport.appspot.com/pypi/docutils"&gt;http://py3ksupport.appspot.com/pypi/docutils&lt;/a&gt;) you can see if the project's support has been picked up yet or not. As I said, forks do qualify for support as well as do projects which have functioning support in version control but have just not done a release yet. This is all rather important for the top projects as listed on the &lt;a href="http://py3ksupport.appspot.com/"&gt;home page&lt;/a&gt;&amp;nbsp;since that is what people will really pay attention to in order to notice Python 3 uptake.&lt;br /&gt;
&lt;br /&gt;
To give people some scope of how much of a difference this curation makes, consider the top 50 projects by downloads for any release. 14 of the top 50 (i.e., 28%) support Python 3 somehow. But if you went by only trove classifiers you would think only 9 project (18%) supported Python 3. Even hard coding modules absorbed into Python's stdlib would leave off 2 of the projects. If you look at latest release downloads you have even bigger support and discrepancies: 16 out of 50 projects support Python 3. But of those, 8 I had to manually flag (4 of which are not from the stdlib). Percentage-wise this manual effort makes a difference and gives a much better indication of how much support there already is for Python 3.&lt;br /&gt;
&lt;br /&gt;
So this is what I have been working on for the past two weeks. I learned a lot about App Engine and creating a scalable website. The whole thing updates every 20 minutes from PyPI in terms of project metdata changes. I also update download totals every day. Long term I hope to add more metrics to gauge what the top projects are (e.g., listed dependencies, Google Code searches, etc.). I also want to develop a Chrome extension which will let a user know when a project supports Python 3 when viewing PyPI even if it doesn't say so (maybe even getting to the point that people can notify me through a button click that the project actually does support Python 3). I also want an API so that people on other websites that use different metrics can have access to the same data I use to mark a project as supported or not. But as of right now, I'm ready to take the weekend off. =)&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/bfWFoRa9CrU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3036978243739097943?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3036978243739097943?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/bfWFoRa9CrU/secret-site-goes-live-python-3-support.html" title="Secret site goes live: Python 3 Support on PyPI" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/03/secret-site-goes-live-python-3-support.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYFQXs4fCp7ImA9Wx9aEk8.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-8890476019953351436</id><published>2011-03-03T23:18:00.000-08:00</published><updated>2011-03-03T23:18:30.534-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-03T23:18:30.534-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, the last days: the website works (so far)!</title><content type="html">The last couple of days I have been working hard to hack together (and I mean &lt;i&gt;hack&lt;/i&gt;; it is not the most elegant code or solution I have ever written) the remaining bits of the website. I am currently waiting for the task queues to finish doing their thing so that I have a complete data set before I go "public" by asking the community for some help with something. But so far things are working out and hopefully I will wake up in the morning to no errors and the data set complete!&lt;br /&gt;
&lt;br /&gt;
The biggest challenge I have run into over the last couple of days is App Engine's &lt;a href="http://code.google.com/appengine/docs/python/taskqueue/overview.html#Quotas_and_Limits"&gt;10K limit on task queue data&lt;/a&gt;. that ain't much data. So I had to do some reworking of my data syncing workflow to use the datastore as a temporary storage solution. It worked out, but I'm sure I am doing something silly. At least I made sure everything happens in a transaction so that if anything fails the task queue will simply try again until it works (hopefully it's a transient failure and doesn't require me to fix some code &amp;nbsp;=) .&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/nnlRmXGE-Nk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8890476019953351436?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8890476019953351436?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/nnlRmXGE-Nk/psf-core-grant-last-days-website-works.html" title="PSF core grant, the last days: the website works (so far)!" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/03/psf-core-grant-last-days-website-works.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcERXY6cCp7ImA9Wx9aEE4.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-8466455938878737323</id><published>2011-03-01T18:13:00.000-08:00</published><updated>2011-03-01T18:13:24.818-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-01T18:13:24.818-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Introducing mnfy</title><content type="html">Remember back in November when I did a &lt;a href="http://sayspy.blogspot.com/2010/11/my-python-minifier-which-was-not-to-be.html"&gt;blog post about an AST-based minifier for Python code&lt;/a&gt;? Remember how I said I gave up on it out of frustration over how the AST represented things in a way that didn't mirror the syntax? Yeah, that "giving up" part didn't sit well with me, so I created &lt;a href="http://pypi.python.org/pypi/mnfy"&gt;mnfy&lt;/a&gt;&amp;nbsp;to help minify/obfuscate Python 3 code.&lt;br /&gt;
&lt;br /&gt;
It's basically a little project that I created which &lt;i&gt;helps&lt;/i&gt;&amp;nbsp;in minifying code. I got over my issues with the AST by simply thinking it through and figuring out exactly which AST nodes needed special treatment (e.g., how to detect an 'elif' clause). Once I did that I was able to work on some of the transforms which is where the fun is.&lt;br /&gt;
&lt;br /&gt;
The code currently doesn't do anything fancy that human beings who like to muck about with minifying/obfuscating Python don't already do:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Eliminates unneeded whitespace&lt;/li&gt;
&lt;li&gt;Minimal parenthesis usage (mostly)&lt;/li&gt;
&lt;li&gt;Uses hexadecimal numbers when it will save on characters&lt;/li&gt;
&lt;li&gt;Combines imports into a single line that are defined in a row&lt;/li&gt;
&lt;li&gt;Drop unused constants (including docstrings)&lt;/li&gt;
&lt;li&gt;Functions into lambda definitions&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
As I said, nothing nuts, but at least takes some of the tedium out. The transformations of the syntax are also separated into safe and unsafe transforms. I consider safe transforms things that are semantically equivalent to what was changed in 99% of the cases (i.e., if you muck with execution frames you are on your own). Unsafe transforms will work in 90% of the cases, but are not exactly semantically equivalent (e.g., lambdas are not entirely equivalent to a defined function). Thus users can choose their exposure to transforms which may or may not break their code. You can also skip transforms all together and simply go with the elimination of whitespace and unneeded formatting characters (e.g., parentheses). In the latter case I am able to minify the entire standard library and still get back the exact same AST.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Anyway, this was just a fun little project that I don't plan to take that seriously (i.e., don't expect massive churn on the code any time soon &amp;nbsp;=). If either minification/obfuscation or working with Python's AST interests you, &amp;nbsp;there is a &lt;a href="http://us.pycon.org/2011/schedule/presentations/184/"&gt;talk on using Python's ast module&lt;/a&gt; and another &lt;a href="http://us.pycon.org/2011/schedule/presentations/137/"&gt;on obfuscating Python code&lt;/a&gt; at PyCon you can attend.&amp;nbsp;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/8nv7G3BkCPA" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8466455938878737323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8466455938878737323?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/8nv7G3BkCPA/introducing-mnfy.html" title="Introducing mnfy" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/03/introducing-mnfy.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4GQ3c6eip7ImA9Wx9aEE0.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-8980038327522338542</id><published>2011-03-01T09:35:00.000-08:00</published><updated>2011-03-01T09:35:22.912-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-01T09:35:22.912-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, day 39: darn scalability</title><content type="html">So the server component for the secret website is nearly complete, when I started to test the site through App Engine's dev appserver, some issues arose which were not triggered by unit tests. So I spent Sunday and yesterday (counting as one day thanks to working on bursts on-and-off) working on fixing those issues.&lt;br /&gt;
&lt;br /&gt;
Otherwise the only other news is that the &lt;a href="http://hg.python.org/devinabox"&gt;Python-Dev In a Box&lt;/a&gt; code is up. Please realize that it &lt;b&gt;will not&lt;/b&gt;&amp;nbsp;work for you! It is currently geared towards using the Hg test repo which is not ready for general use (e.g., it's missing some commits that landed in svn). I also am going on an assumption a patch I submitted to coverage.py about a __main__.py file for the repo directory gets accepted, and so I have a file I manually copy over in that instance until that happens. In other words, if you decide to play with the code realize that it probably won't work and so bug reports about it not running are probably premature. =)&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/3Y4uhXYix7w" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8980038327522338542?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/8980038327522338542?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/3Y4uhXYix7w/psf-core-grant-day-39-darn-scalability.html" title="PSF core grant, day 39: darn scalability" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/03/psf-core-grant-day-39-darn-scalability.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQCQHk6fip7ImA9Wx9bF0U.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-6503267196291301656</id><published>2011-02-26T22:32:00.000-08:00</published><updated>2011-02-26T22:32:41.716-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-26T22:32:41.716-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, days 37 &amp; 38: making Python-Dev In a Box a reality</title><content type="html">I got enough positive feedback on the Python-Dev In a Box idea from my &lt;a href="http://sayspy.blogspot.com/2011/02/psf-core-grant-day-36-maintaining.html"&gt;last blog post&lt;/a&gt; that I decided to implement it. Over yesterday and today I have been writing some scripts to help bootstrap people into contributing. I will make the code and repository public as soon as I can get the remote repository at hg.python.org created.&lt;br /&gt;
&lt;br /&gt;
So the goal of this project was to make it easy for people to jump in and start contributing at a sprint or on their way home from a conference. That meant providing the code, tools, and information needed to contribute. It also meant doing as much upfront for people as possible so as to not waste time for what everyone would end up doing along with not requiring a network connection. And all of this, at max, needs to fit in 700 MB on a CD.&lt;br /&gt;
&lt;br /&gt;
First, there is a script called make_a_box.py which creates a Python-Dev In a Box instance. It will prompt you for what you want to include in the box:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;CPython (from an Hg repository at the moment, but I might patch it to be from svn if Hg is not ready by PyCon)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.python.org/devguide/"&gt;Devguide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.python.org/dev/peps/"&gt;PEPs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nedbatchelder.com/code/coverage/"&gt;coverage.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.hg-scm.org/"&gt;Mercurial&lt;/a&gt; and &lt;a href="http://tortoisehg.bitbucket.org/"&gt;TortoiseHg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.microsoft.com/express/"&gt;Visual C++ Express&lt;/a&gt;&amp;nbsp;(the Web installer)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
When reasonable it will build what is provided. In the case of CPython and the various bits of documentation, the docs get built. For coverage.py it runs it so you have a basic coverage report for people to work off of.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
For users, I included two extra scripts. One simply builds CPython (on UNIX). While building is very straightfoward (and &lt;a href="http://docs.python.org/devguide/setup.html#unix"&gt;documented in the devguide&lt;/a&gt;), I needed the functionality for generating the coverage report. Since I needed the code anyway I figured I would make it a stand-alone script. About the only real perk to it is that it uses multiprocessing.cpu_count() to run the Makefile with as many cores as you have (although CPython compiles in a fairly linear fashion so extra cores doesn't do that much).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I also provided a script that runs the test suite in the fastest, most rigorous way possible. Once again, while &lt;a href="http://docs.python.org/devguide/runtests.html#running"&gt;documented in the devguide&lt;/a&gt;, people can get a little lazy when it comes to running the entire test suite, so hopefully having a script that uses the "best" options will lead to more rigorous testing overall.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
My plan is to create a Box for the &lt;a href="http://us.pycon.org/2011/sprints/projects/"&gt;PyCon sprints&lt;/a&gt; so that people attending the sprint can simply copy from a CD or flash drive everything they need to get going. This should speed up people getting started, leading to more productivity.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/YrqhOgE4KHI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/6503267196291301656?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/6503267196291301656?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/YrqhOgE4KHI/psf-core-grant-days-37-38-making-python.html" title="PSF core grant, days 37 &amp; 38: making Python-Dev In a Box a reality" /><author><name>Brett Cannon</name><uri>https://plus.google.com/115362263245161504841</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-W02X_Q1zdSo/AAAAAAAAAAI/AAAAAAAAYmM/H0hrtiNwdlI/s512-c/photo.jpg" /></author><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-days-37-38-making-python.html</feedburner:origLink></entry></feed>
