<?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: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;Ck8CQn06eCp7ImA9WhVUFUU.&quot;"><id>tag:blogger.com,1999:blog-20144447</id><updated>2012-05-20T23:14:23.310-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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>481</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;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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-2969136173953826690?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-1179193750413927939?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8878728228228327079?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-277617608959410728?l=sayspy.blogspot.com' alt='' /&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8633124756751933901?l=sayspy.blogspot.com' alt='' /&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7049292135010812002?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-45319338764901705?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8061719703454197921?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-3205824887431592899?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-395568833907615931?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-2598909673565259431?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-5768404123373137545?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-6088657966087326699?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-9204404256444674504?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-3036978243739097943?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8890476019953351436?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8466455938878737323?l=sayspy.blogspot.com' alt='' /&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8980038327522338542?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-6503267196291301656?l=sayspy.blogspot.com' alt='' /&gt;&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://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-days-37-38-making-python.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcFQXY6cCp7ImA9Wx9bFk0.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-1869505820114841667</id><published>2011-02-24T19:20:00.000-08:00</published><updated>2011-02-24T19:20:10.818-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-24T19:20:10.818-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, day 36: maintaining a website is a pain, Hg, and Python-Dev In a Box</title><content type="html">I'm &lt;i&gt;this&lt;/i&gt;&amp;nbsp;close to having the data maintenance aspect of the "secret" website done, but came up short when I forgot that entities in App Engine cannot be stored in a transaction unless they are in the same entity group. Since I have tens of thousands of entities, putting them all in a single entity group seems stupid, so I will simply have to break out another worker to be called from a task queue in order to process each entity one by one (at least I can still batch the external network calls). Bah. So close!&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
While nothing to do directly with me, on the behalf of himself and Georg Brandl, Antoine Pitrou announced a &lt;a href="http://mail.python.org/pipermail/python-dev/2011-February/108270.html"&gt;test Mercurial repository for (C)Python&lt;/a&gt;. I'm obviously excited about this since I spearheaded this whole &lt;s&gt;debacle&lt;/s&gt; movement to switch from svn to hg back in late 2008, making the decision of hg with Guido at PyCon 2009. It looks like there is a slight chance we might actually get this done in the near future (since Antoine and Georg are pushing this the last little distance I can't speak to whether they will get it done by PyCon 2011, but it would be neat if they did).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
A rather nice side-effect of switching to Mercurial is the smaller amount of space that a Mercurial repo of Python takes up compared to Subversion. This led to a slight discussion #python-dev about creating a Python-Dev In a Box. The idea is that to help spur contributors one could put the Mercurial repo, the &lt;a href="http://docs.python.org/devguide/"&gt;devguide&lt;/a&gt; (pre-built, but also along with the &lt;a href="http://hg.python.org/devguide/"&gt;hg repo&lt;/a&gt;), &lt;a href="http://www.hg-scm.org/"&gt;Mercurial&lt;/a&gt; itself (including &lt;a href="http://tortoisehg.bitbucket.org/"&gt;TortoiseHg&lt;/a&gt;), pre-build the docs (so that people have a copy of Sphinx and such which can also be used to build , and anything else I could think of (&lt;a href="http://svn.python.org/view/peps/"&gt;PEPs checkout&lt;/a&gt;? &lt;a href="http://www.microsoft.com/express/"&gt;Visual Studio Express&lt;/a&gt; installer? coverage.py along with coverage results?) on a CD or flash drive so that people have everything they need to start hacking on Python. And by putting it on physical media it makes it easy to bootstrap everyone in the room quickly without slamming the network. It also provides everyone even the ability to get going while offline (e.g., "Can't stay for the sprint? Take a CD and start on the plane home (if you are not on Windows as that requires downloading Visual Studio Express)!"). Hell, think if this became a bag stuffer at PyCon! I wonder if that would increase contributions?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-1869505820114841667?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/l-rnUOW9Ntc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/1869505820114841667?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/1869505820114841667?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/l-rnUOW9Ntc/psf-core-grant-day-36-maintaining.html" title="PSF core grant, day 36: maintaining a website is a pain, Hg, and Python-Dev In a Box" /><author><name>Brett Cannon</name><uri>https://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-day-36-maintaining.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQCQXY4eip7ImA9Wx9bFUw.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-4726600001365758307</id><published>2011-02-23T17:52:00.000-08:00</published><updated>2011-02-23T17:52:40.832-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-23T17:52:40.832-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, days 33, 34, &amp; 35: Python 3.2.0, fighting personal feature creep</title><content type="html">First off, for those of you who don't know, &lt;a href="http://www.python.org/download/releases/3.2/"&gt;Python 3.2.0&lt;/a&gt; was released on February 20th (which serendipitously happens to &lt;a href="http://www.google.com/buzz/gvanrossum/KuS7a5hLSVn/gvanrossum-The-first-Python-version-0-9-0-was"&gt;correspond to the 20 year anniversary of Python 0.9&lt;/a&gt;, the first release of Python). To celebrate Python being a score old, why don't you help port a project to Python 3.2.0? =)&lt;br /&gt;
&lt;br /&gt;
With Python 3.2.0 out the door, the development branch of Python was open to commits again. I was able to commit all but one of my patch queue I have been sitting on for over a month. This means that the in-development branch of Python can now run the test suite under &lt;a href="http://nedbatchelder.com/code/coverage/"&gt;coverage.py&lt;/a&gt; without any special patches. I also fixed a bunch of static analysis warnings found by Clang. I am ignoring the time burned on trying to fix test_zlib failing under OS X as people much wiser than I at mmap solved that one. I also fixed the new crypt module changes to be PEP 8 compliant and simplified the API a little.&lt;br /&gt;
&lt;br /&gt;
As for the secret project, I am working on not letting feature creep get the better of me. I scaled it back slightly so that it won't start out life with as much stuff since it didn't need it everything. But then I also thought of a cool way to get more people to participate with the website through a Chrome extension. Out with one feature, in with another.&lt;br /&gt;
&lt;br /&gt;
But I am reaching the ability to launch in private beta in about a week. I don't see why I won't have this ready to go for public consumption (in a rather rough state) by PyCon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-4726600001365758307?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/oo_tCyXnHK8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/4726600001365758307?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/4726600001365758307?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/oo_tCyXnHK8/psf-core-grant-days-33-34-35-python-320.html" title="PSF core grant, days 33, 34, &amp; 35: Python 3.2.0, fighting personal feature creep" /><author><name>Brett Cannon</name><uri>https://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-days-33-34-35-python-320.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IMQnc8cSp7ImA9Wx9bEks.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-3413904493472996319</id><published>2011-02-20T20:13:00.000-08:00</published><updated>2011-02-20T20:13:03.979-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-20T20:13:03.979-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, day 30, 31, and 32: lots of testing, moving on to data maintenance</title><content type="html">In a previous blog post I mentioned &lt;a href="http://sayspy.blogspot.com/2011/02/psf-core-grant-days-28-29-learning-hard.html"&gt;my refactoring/testing strategy&lt;/a&gt; for the website I am developing. Friday was all about implementing that strategy. Even without touching the network, my tests were good enough to lead to only two very shallow bugs that needed fixing. At that point I am basically caught up in my testing regimen.&lt;br /&gt;
&lt;br /&gt;
That means new features! But yesterday and today have been a back-and-forth battle between trying to do a good job and worrying too much about rare edge cases and features that are not needed. Since the data only needs to portray details in a rough level and only for a subset of the available data, I realized I need to relax and not sweat every single little detail that could come up. It's just as easy to run an occasional sanity check to rectify any data drift that may come up.&lt;br /&gt;
&lt;br /&gt;
And a tip to those using &lt;a href="http://code.google.com/p/nose-gae/"&gt;nose-GAE&lt;/a&gt;, if you get an odd error about not being able to delete a datastore file, it probably means you have a syntax error somewhere.&lt;br /&gt;
&lt;br /&gt;
And a tip for those using &lt;a href="http://chrome.google.com/"&gt;Google Chrome&lt;/a&gt;: be aware that if you are manually triggering things through a GET request, Chrome's prefetching of pages can cause you to accidentally request twice. This was a problem for me as I was doubling the stuff I was putting on task queues and it took me a while to realize why.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-3413904493472996319?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/q5U2JIxJy_I" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3413904493472996319?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3413904493472996319?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/q5U2JIxJy_I/psf-core-grant-day-30-31-and-32-lots-of.html" title="PSF core grant, day 30, 31, and 32: lots of testing, moving on to data maintenance" /><author><name>Brett Cannon</name><uri>https://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-day-30-31-and-32-lots-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08MRX47cCp7ImA9Wx9bEE0.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-3796625758134169597</id><published>2011-02-17T22:18:00.000-08:00</published><updated>2011-02-17T22:18:04.008-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-17T22:18:04.008-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Register for PyCon *NOW* if you actually plan to attend</title><content type="html">A trusted chair of &lt;a href="http://us.pycon.org/2011/home/"&gt;PyCon US 2011&lt;/a&gt;, &lt;a href="http://www.haynesboone.com/van_lindberg/"&gt;Van&lt;/a&gt; &lt;a href="http://www.lindbergd.info/"&gt;Lindberg&lt;/a&gt;, did a&lt;a href="http://us.pycon.org/2011/blog/2011/02/16/pycon-2011-behind-scenes/"&gt; post explaining some of the behind-the-scenes issues&lt;/a&gt; that must be worked out when organizing the conference. It's an interesting post that's worth reading.&lt;br /&gt;
&lt;br /&gt;
But one of the key take-aways from that post is that the hotel space is going quickly. We have already taken &lt;a href="http://twitter.com/#!/VanL/status/37986908067991552"&gt;105% of our allotted space&lt;/a&gt;. It's already &lt;a href="http://twitter.com/#!/VanL/status/38069386384379904"&gt;projected that we will sell out PyCon&lt;/a&gt; this year. Make sure you register if you have not already else you may very well find yourself unable to attend no matter how badly you want to come.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-3796625758134169597?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/HUlK4tP8pf0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3796625758134169597?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/3796625758134169597?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/HUlK4tP8pf0/register-for-pycon-now-if-you-actually.html" title="Register for PyCon *NOW* if you actually plan to attend" /><author><name>Brett Cannon</name><uri>https://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/register-for-pycon-now-if-you-actually.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08BRn46fSp7ImA9Wx9bEE0.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-7650263514051428443</id><published>2011-02-17T20:04:00.000-08:00</published><updated>2011-02-17T20:04:17.015-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-17T20:04:17.015-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, days 28 &amp; 29: learning the hard way that you need tests</title><content type="html">My little skunkworks website got cleared to be worked on, so I have shifted my focus to it. I think I am going to keep it a secret until &lt;a href="http://us.pycon.org/2011/home/"&gt;PyCon&lt;/a&gt; and announce it during a lightning talk for fun.&amp;nbsp;But just because the subject of my work is a secret doesn't mean the process of creating the website needs to be kept from the public (even if it means I have to admit to what I am doing early; being secretive is not exactly critical).&lt;br /&gt;
&lt;br /&gt;
I must admit that most of my experience in creating websites is relegated to either simple stuff or more JavaScript-heavy work. This is turning out to be the first website where there is a serious back-end that has offline workers, constantly updating data, etc. In other words it is a learning experience for me.&lt;br /&gt;
&lt;br /&gt;
The first lesson is that I can't be sloppy with this website. Back on Sunday I started to slap together the website on &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;&amp;nbsp;on my machine, simply coding away until I thought I reached a point where I could actually examine some data. I was using &lt;a href="http://code.google.com/appengine/docs/python/taskqueue/"&gt;task queues&lt;/a&gt; for the first time and trying to coordinate all of this communication with various queues running at various rates with different workers, etc. In other words I over-engineered.&lt;br /&gt;
&lt;br /&gt;
But even worse is that I was not doing any proper testing. I figured I might just do some hand-driven tests on a subset of data to make sure things were working out. But my slap-dash coding quickly became a hindrance as I ran into several import errors thanks to me not paying attention and making sure to add the proper import statement. With the turn-around of launching a page which populated a task queue being long, I knew that I just couldn't keep going like this.&lt;br /&gt;
&lt;br /&gt;
And so I knew I had to recode for testing. But how the heck do you test a website, let alone an App Engine website? I mean I know how to write proper unit tests, functional tests, etc., but I didn't know the best way to handle that for a website that has to run under some heavy infrastructure that has to be available.&lt;br /&gt;
&lt;br /&gt;
This called for some research to even get tests executing. I stumbled across &lt;a href="http://code.google.com/p/nose-gae/"&gt;nose-gae&lt;/a&gt; which seemed to give me what I needed to get the tests executed if I was willing to use &lt;a href="http://somethingaboutorange.com/mrl/projects/nose/1.0.0/"&gt;nose&lt;/a&gt; (which I was). I even tried to be a good little developer and work under &lt;a href="http://pypi.python.org/pypi/virtualenv"&gt;virtualenv&lt;/a&gt;, but I ran up against odd path issues involving App Engine that I simply did not want to try to diagnose after an attempt to use &lt;a href="http://code.google.com/p/gaeunit/"&gt;gaeunit&lt;/a&gt; left me wanting (not enough traceback info to debug well). Luckily nose and nose-gae were the only things I felt the need to actually install so I didn't totally screw up my Python 2.5 install.&lt;br /&gt;
&lt;br /&gt;
With tests runnable, I then had to decide how the heck I was going to do this. And that's when I decided I needed to refactor the hell out of my code. Being an App Engine app that is (at least currently) using no web framework, every URL resolves to a &lt;a href="http://code.google.com/appengine/docs/python/tools/webapp/requesthandlers.html"&gt;request handler class&lt;/a&gt;. That means there is at least a get() or post() method on each class. So I made the decision that all request handling (e.g., getting what is in some POST argument but not even decoding the JSON) and all response handling (e.g., writing back out any HTML) would be handled in the get/post method, but nothing more; essentially they are gutted to the point of simply stitching together method calls, as one typically should when there is I/O involved. I then broke code down into helper methods as necessary in order to think about the functionality in the way I needed to. I also put all &lt;a href="http://code.google.com/appengine/docs/python/datastore/transactions.html"&gt;transaction&lt;/a&gt; code in its own method since I am purposefully keeping that work to a computational minimum. This allows me to &lt;a href="http://pypi.python.org/pypi/mock/"&gt;mock&lt;/a&gt; out things like task queue usage in order to verify what I want to happen is going on without worrying about App Engine actually using some task queue and having to clean that up manually later (handling actual &lt;a href="http://code.google.com/appengine/docs/python/datastore/"&gt;datastore&lt;/a&gt; work is no big deal so I am happy to let that actually occur with proper test cleanup).&lt;br /&gt;
&lt;br /&gt;
All of this leads to me writing abstracted, modular code where I can test non-network, non-App Engine code quickly and easily and then purposefully cleaning up or mock out as needed when I do need to work with App Engine's assets. At this point I have not written tests for the actual website page requests as the get()/post() methods as they are dirt-simple and they are just being called by App Engine task queue events (but eventually I will once I decide how I want to handle that specific case; &lt;a href="http://pythonpaste.org/webtest/"&gt;webtest&lt;/a&gt;?).&lt;br /&gt;
&lt;br /&gt;
What is the lesson in all of this? Don't be sloppy. Assume you will have to test your code eventually, forcing you to write code in a fashion that makes the code easy to test. And then actually bother to test your code. Dealing with the network or APIs that have no way to undo or cancel an event programmatically (e.g., something in a task queue) should not stop you from writing tests as there are ways to isolate these things such that they are not a burden.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7650263514051428443?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/dDldSA0REzY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/7650263514051428443?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/7650263514051428443?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/dDldSA0REzY/psf-core-grant-days-28-29-learning-hard.html" title="PSF core grant, days 28 &amp; 29: learning the hard way that you need tests" /><author><name>Brett Cannon</name><uri>https://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-days-28-29-learning-hard.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QDRHY5fSp7ImA9Wx9UF0k.&quot;"><id>tag:blogger.com,1999:blog-20144447.post-4576467319462057504</id><published>2011-02-14T21:56:00.000-08:00</published><updated>2011-02-14T21:56:15.825-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-14T21:56:15.825-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>PSF core grant, day 27: little details, a secret, and a progress report</title><content type="html">Started out the day creating a &lt;a href="http://psf.upfronthosting.co.za/roundup/meta/issue377"&gt;patch to link from the issue tracker to the devguide&lt;/a&gt;. There have been a couple people who have asked me to have the issue tracker fields link to the devguide to give a better explanation. Plus updating the docs is easier than the tracker.&lt;br /&gt;
&lt;br /&gt;
But what really took up most of my time today (and yesterday, but I had errands throughout today so I am counting this as a day's work) is a little skunkworks project I started working on related to Python 3 and combating some (accidental) FUD that seems to keep coming up that really needs to get squashed.&lt;br /&gt;
&lt;br /&gt;
Anyway, I also figured I would summarize what the heck I have done as part of my grant as I have finished day 27 of 41 (and I need to summarize for the PSF board this week). I completed the &lt;a href="http://docs.python.org/devguide/"&gt;devguide&lt;/a&gt;, which I have wanted to do for literally years. There is also a &lt;a href="http://hg.python.org/devguide/branches"&gt;branch&lt;/a&gt; of it already prepared for when the switch to Hg occurs. This also led to various patches that make sure the stdlib can have its test &lt;a href="http://bugs.python.org/issue10990"&gt;coverage&lt;/a&gt; &lt;a href="http://bugs.python.org/issue10992"&gt;measured&lt;/a&gt;, &lt;a href="http://bugs.python.org/issue8914"&gt;fixed&lt;/a&gt; a bunch of static analysis warnings from Clang, and have &lt;a href="http://bugs.python.org/issue10966"&gt;import failures not implicitly represent a skipped test&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I wrote a &lt;a href="http://docs.python.org/dev/howto/pyporting.html"&gt;HOWTO on how to port a Python 2 project to Python 3&lt;/a&gt;. Now the community finally has a single document to read to at least get started in porting instead of having to pull up various blog posts on the subject.&lt;br /&gt;
&lt;br /&gt;
All of this and I am three days behind "schedule" of ending my grant come March 1 (unless my math is wrong and this really isn't the 30th weekday since January 4th, inclusive). Overall I'm happy with what I have done and I am hoping the remaining 14 days are just as productive.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-4576467319462057504?l=sayspy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CoderWhoSaysPy/~4/ZqAX8bdaIXU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/4576467319462057504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/20144447/posts/default/4576467319462057504?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CoderWhoSaysPy/~3/ZqAX8bdaIXU/psf-core-grant-day-27-little-details.html" title="PSF core grant, day 27: little details, a secret, and a progress report" /><author><name>Brett Cannon</name><uri>https://profiles.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/AAAAAAAAFc4/kZOmMC-LiaE/s512-c/photo.jpg" /></author><feedburner:origLink>http://sayspy.blogspot.com/2011/02/psf-core-grant-day-27-little-details.html</feedburner:origLink></entry></feed>

