<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-20144447</id><updated>2009-07-03T12:45:36.082-07:00</updated><title type='text'>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='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/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'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>380</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-20144447.post-3625672704173250832</id><published>2009-06-27T15:46:00.003-07:00</published><updated>2009-06-28T12:12:03.101-07:00</updated><title type='text'>Python 3.1 is out</title><content type='html'>As &lt;a href="http://twitter.com/gutworth/status/2363572340"&gt;Benjamin Peterson tweeted&lt;/a&gt;, &lt;a href="http://www.python.org/download/releases/3.1/"&gt;Python 3.1&lt;/a&gt; is now available. As always you can read about &lt;a href="http://docs.python.org/3.1/whatsnew/3.1.html"&gt;what's new&lt;/a&gt;. Anyone using Python 3 for anything should upgrade as there are some major performance improvements in 3.1 that will make your life better (that includes the new --with-computed-gotos configure flag).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And just to remind people, &lt;a href="http://www.python.org/dev/peps/pep-0370/"&gt;PEP 370&lt;/a&gt; exists to help you manage your Python installation.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-3625672704173250832?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/3625672704173250832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/06/python-31-is-out.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/3625672704173250832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/3625672704173250832'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/06/python-31-is-out.html' title='Python 3.1 is out'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-303828573459613949</id><published>2009-06-02T11:38:00.003-07:00</published><updated>2009-06-02T13:08:09.930-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='import'/><category scheme='http://www.blogger.com/atom/ns#' term='importlib'/><title type='text'>Lazy imports in 25 lines of code</title><content type='html'>For some unknown reason to me, I found myself thinking about lazy importing on my way home from school. Now I have never actually dived into the topic before so I had no preconceived notions of how to solve the problem. I do know that people like to have imports be lazy so that the startup time of their applications are not dominated by imports of modules that they do not need immediately, if at all. Many projects have replicated their own solution to this problem such as &lt;a href="http://bazaar.launchpad.net/~bzr/bzr/trunk/annotate/head%3A/bzrlib/lazy_import.py"&gt;bzr&lt;/a&gt; and &lt;a href="http://selenic.com/repo/index.cgi/hg-stable/file/107af208ed0b/mercurial/demandimport.py"&gt;hg&lt;/a&gt;. This has even gone as far as Greg Ewing &lt;a href="http://mail.python.org/pipermail/python-ideas/2008-October/002193.html"&gt;proposing actual syntax support on python-ideas&lt;/a&gt; and Christian Heimes using lazy imports as a motivating factor for &lt;a href="http://www.python.org/dev/peps/pep-0369/"&gt;post import hooks&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;While the solution varies, the general agreed upon solution is to call some custom function that will return a module proxy. That proxy triggers the actual import once the module is actually used in some meaningful way, such as when an attempt is made to access an attribute. I also assumed that people either used a custom importer (meta path or not) or a custom &lt;code&gt;__import__&lt;/code&gt; function. But beyond that I had no clue how people solved the issue. The importer solution can be seen in a &lt;a href="http://code.activestate.com/recipes/473888/"&gt;cookbook recipe&lt;/a&gt; and the custom function can be seen in &lt;a href="http://peak.telecommunity.com/DevCenter/Importing"&gt;peak.util.import&lt;/a&gt; (&lt;a href="http://svn.eby-sarna.com/Importing/peak/util/imports.py?view=markup"&gt;source&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Going in blind on this, I started to think about what it would take to pull this off using &lt;a href="http://docs.python.org/dev/py3k/library/importlib.html"&gt;importlib&lt;/a&gt; in Python 3.1 for Python source. I was not going to worry about built-in modules and the like as importing those types of modules are much cheaper compared to importing Python source or bytecode. And I wanted to solution to be as simple as possible since I was doing this for fun, not as an actual robust solution to a problem I had.&lt;br /&gt;&lt;br /&gt;With those goals in mind, I realized that I needed to come up with a lazy loader that could be subclassed for ease of use. I also knew I needed to come up with module proxy object that would trigger an import the instant an attempt was made to access an attribute. Seems simple enough, but obviously it isn't obvious.&lt;br /&gt;&lt;br /&gt;First problem I had to solve was how the module proxy would get at the real loader when it was eventually needed. That was quickly solved by assigning the lazy loader to &lt;code&gt;__loader__&lt;/code&gt; and treating the class as a mix-in. Assuming the lazy loader class name was &lt;code&gt;LazyMixin&lt;/code&gt; and I set up the inheritance correctly, I could get at the real loader from within the module proxy with &lt;code&gt;super(LazyMixin, self.__loader__)&lt;/code&gt;. By re-assigning the resulting object to &lt;code&gt;__loader__&lt;/code&gt; I would continue to have the actual loader doing the loading on the module as well have a consistent way to get at the loader I was after. Assuming a module proxy class named LazyModule, the code looks like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class LazyMixin:&lt;br /&gt;&lt;br /&gt;    def load_module(self, name):&lt;br /&gt;        module = LazyModule(name)&lt;br /&gt;        module.__loader__ = self&lt;br /&gt;        sys.modules[name] = module&lt;br /&gt;        return module&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With that problem solved I turned my attention to the module proxy. After some mishaps with trying to dynamically set &lt;code&gt;__getattr__&lt;/code&gt; I had an epiphany: I could simply reset &lt;code&gt;__class__&lt;/code&gt; to a class that lacked the &lt;code&gt;__getattribute__&lt;/code&gt;. By having both the lazy module class with &lt;code&gt;__getattribute__&lt;/code&gt; defined and the module class that &lt;code&gt;__class__&lt;/code&gt; gets set to inherit from &lt;code&gt;types.ModuleType&lt;/code&gt; I could make sure that the module instance was always consistent in terms of its type. This all led to the following module objects:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  class Module(types.ModuleType):&lt;br /&gt;    pass&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  class LazyModule(types.ModuleType):&lt;br /&gt;&lt;br /&gt;    def __getattribute__(self, attr):&lt;br /&gt;        self.__class__ = Module&lt;br /&gt;        self.__loader__ = super(LazyMixin, self.__loader__)&lt;br /&gt;        self.__loader__.load_module(self.__name__)&lt;br /&gt;        return getattr(self, attr)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The final problem to work out was how to make sure that the module instance was what got initialized by the import so that all pre-existing references to the module instance worked after the import. The obvious way is to make the module proxy act as an actual proxy; you could store the initialized module in the proxy and forward all attribute requests to the initialized module using &lt;code&gt;__getattribute__&lt;/code&gt;. But that has a performance penalty that seems unnecessary and I had a gut feeling there had to be a more elegant solution.&lt;br /&gt;&lt;br /&gt;That more elegant solution is module reloading. If you look at &lt;a href="http://www.python.org/dev/peps/pep-0302/"&gt;PEP 302&lt;/a&gt; you will notice that to support module reloading that a loader is expected to reuse the module found in &lt;code&gt;sys.modules&lt;/code&gt; when performing a load. This makes sure that existing references to a module continue to work as the module instance doesn't change, just its &lt;code&gt;__dict__&lt;/code&gt;. So by sticking the module proxy instance into &lt;code&gt;sys.modules&lt;/code&gt; the real loader would use that module object for the initialization, letting all pre-existing references to continue to be valid.&lt;br /&gt;&lt;br /&gt;It turns out that all of this was enough for a proof-of-concept to work! By creating a class that inherited both the lazy loader and importlib's private Python source file loader I was able to defer actual importing of a source file until an attribute on the module was accessed. And the best part was that the only requirement of the real loader was that it follow the rules set out in &lt;a href="http://www.python.org/dev/peps/pep-0302/"&gt;PEP 302&lt;/a&gt; which importlib provides with &lt;code&gt;importlib.util.module_for_loader&lt;/code&gt;. And an even cooler thing is that since the lazy loader is a mix-in that only overrides &lt;code&gt;load_module&lt;/code&gt; all other methods from the real loader are accessible, meaning the lazy loader allows for the use of introspection APIs such as &lt;code&gt;importlib.abc.InspectLoader&lt;/code&gt; to continue to work! And the greatest perk of all is that since it works with loaders it is completely transparent to the import statement, removing any need to use a custom function to make this work!&lt;br /&gt;&lt;br /&gt;To see the proof-of-concept which is NOT PRODUCTION QUALITY -- remember it is using private APIs from importlib which could easily disappear at any time -- see &lt;a href="http://paste.pocoo.org/show/120655/"&gt;this paste bin&lt;/a&gt;. I am sure the code should be more robust somehow, but I am rather pleased with the solution is only 20 source lines and appears to work at least in a really dead-simple example. If people actually like this approach and think they would find it useful then leave a comment and I will see if I can be persuaded to package it up and write the proper tests so that I would be willing to put this up on &lt;a href="http://cheeseshop.python.org"&gt;the Cheeseshop&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-303828573459613949?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/303828573459613949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/06/lazy-imports-in-25-lines-of-code.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/303828573459613949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/303828573459613949'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/06/lazy-imports-in-25-lines-of-code.html' title='Lazy imports in 25 lines of code'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-7690183959399092578</id><published>2009-05-30T13:37:00.004-07:00</published><updated>2009-05-30T16:02:21.545-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python-dev'/><title type='text'>The staleness of the standard library and adding new things</title><content type='html'>If you happen to follow certain members of python-dev on &lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt; you may have noticed a discussion going on over &lt;a href="http://www.zedshaw.com/"&gt;Zed Shaw's&lt;/a&gt; "&lt;a href="http://www.zedshaw.com/blog/2009-05-29.html"&gt;Curing Python's Neglect&lt;/a&gt;" post about inconsistencies in the language and the standard library, focusing mostly on the latter. This caused some people to say Zed should be &lt;a href="http://www.lindbergd.info"&gt;lindberg'd&lt;/a&gt; (link is currently down) for complaining about the state of Python's standard library without offering solutions. This then led to Zed &lt;a href="http://zedshaw.com/blog/2009-05-30.html"&gt;responding&lt;/a&gt; about how there is a double-standard for accepting changes between Python committers and everyone else which has led to crap making it into the standard library.&lt;br /&gt;&lt;br /&gt;There seems to be a misunderstanding here that I don't think is isolated to Zed (and thus this post is not meant to be picking specifically on Zed, he just happened to spark the discussion) involving Python's history and how things operate over on python-dev that I would like to clear up.&lt;br /&gt;&lt;br /&gt;I want to start off by acknowleding the fact that the standard library is far from perfect. There are modules in there that are of subpar quality when compared to other parts of the standard library. And even those that are in there and are considered good can have some inconsistencies in their APIs that can make them enfuriating to use on occasion. There is work that could stand to happen to clean up some things.&lt;br /&gt;&lt;br /&gt;Today, to get something added to the standard library, we ask that the code be considered best-of-breed by the community, that the developer promise to maintain the code, and that the maintenance happen within Python's development process and not outside of it. There can be a PEP involved depending on how large the code is and how much of a fight there is to get the code included. And of course this is all dependent on whether the core developers believe the module has enough widespread usefulness to warrant adding it to the standard library.&lt;br /&gt;&lt;br /&gt;But historically these requirements are a recent turn of events. I would say that these requirements for inclusion into the standard library did not start to be seriously enforced until some time during the Python 2.5 development cycle which started in November 2004 and ended in September 2006. If you look at the standard library a lot of it predates 2.5 by several releases. If you look at the modules that Zed said could use some improvements you will notice that none of them were added to the standard library recently (or even in the standard library as Zed mistakenly thought that setuptools and easy_install were):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;os: 1992 (I don't even know what release that is)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;time: 1990 (less than a year after Python's creation!)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;datetime: 2.3&lt;br /&gt;&lt;/li&gt;&lt;li&gt;email: 2.2&lt;/li&gt;&lt;/ul&gt;My point is that if you look at a module in the standard library and it seems a little stale and that the API could have possibly used some more public vetting then it probably could have but was accepted anyway. People need to realize that Python was started by Guido to scratch an itch and just happened to turn into this massively popular programming language. Python's popularity took off starting shortly after the first PyCon in 2003, IMO. But because the growth was organic python-dev did not realize how much more careful we had to be with standard library inclusions until a few years later. Back before we instituted more stringent acceptance requirements things were added simply if people offered up the code, were willing to maintain it, and python-dev thought it would be useful.&lt;br /&gt;&lt;br /&gt;But admittedly, even today some modules get to short-circuit the acceptance process. Importlib is a perfect example of this as I didn't have to put it out there for a year to make sure people thought it was best-of-breed. I didn't have to write up a PEP to vet the API. The only thing I had going for me was a known need for what importlib provides. Otherwise the code went in because I wanted it to go in and I happen to be in a position where I can make that simply happen.&lt;br /&gt;&lt;br /&gt;But I skipped the steps only because of other things I did. I skipped the year-long acceptance by the community as I was targetting Python 3.0 which was not released as final yet. I also blogged extensively about importlib and its API so it was at least discussed publicly somewhere. There were several core developers I talked with about the API and who also watched every commit I made with interest and provided feedback. I talked with people at PyCon about this stuff. There is a reason I spent &lt;span style="font-weight: bold;"&gt;years&lt;/span&gt; working on importlib.&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;But importlib is an exception, not the rule. If my bootstrapping goal did not exist importlib would have existed externally for at least a year before I tried to bring it into the standard library. And if I had gotten any realistic pushback from python-dev I would have waited for inclusion, but thankfully I didn't receive any. And trust me when I say that people on python-dev are quite happy to share their opinion if they think something is a bad idea. While people who have proven themselves do get to skip some steps, don't think that they get to do whatever they want to the standard library.&lt;br /&gt;&lt;br /&gt;With all of this in mind, how should modules get fixed? If an API is truly deemed poor and in need of a replacement it can either grow a new API next to the old one or we introduce a new module to make the old module obsolete. Doing the former is nice for stupid little API mistakes, but does require working properly with the pre-existing module which might be a hinderance.&lt;br /&gt;&lt;br /&gt;Adding a new module breaks cleanly from the old module, allowing a new API to exist from scratch. But this has the issue of being a much larger burden for support as there will simply be more code. There are possible stability issues, etc. Even if code has existed out in the public for a year does not guarantee top-notch quality.&lt;br /&gt;&lt;br /&gt;And of course this all assumes that an API is actually fundamentally broken. Minor issues can be overlooked in the name of prior knowledge. When we add something to python-dev we are essentially asking every Python developer out there to learn about this new code and consider using it which is quite the mental burden if you have been using the older API for years. And it is also possible that you are in a minority in thinking it is broken.&lt;br /&gt;&lt;br /&gt;This is all rather complicated and nuanced. Coming up with a solution that pleases everyone is impossible. But python-dev continues to try to do its best and hopefully that does please most people.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7690183959399092578?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/7690183959399092578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/05/staleness-of-standard-library-and.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7690183959399092578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7690183959399092578'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/05/staleness-of-standard-library-and.html' title='The staleness of the standard library and adding new things'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-7879848734023692755</id><published>2009-05-08T15:46:00.002-07:00</published><updated>2009-05-08T15:52:41.698-07:00</updated><title type='text'>Month one of my python-dev sabbatical</title><content type='html'>It now has been roughly a month since I disabled subscriptions for practically every mailing list I belong to. Initially I had to get used to the fact that checking Gmail constantly for new mail was a fruitless exercise. Otherwise it's been nice.&lt;br /&gt;&lt;br /&gt;I definitely have more time on my hands. &lt;a href="http://mail.python.org/mailman/listinfo/python-dev"&gt;Python-dev&lt;/a&gt; has been my hobby for so long I had somewhat forgotten what it was like to just work on a coding project purely for fun and just for myself. Not having to answer to the Python community for the quality of my code or test coverage, not having to document everything, or have to argue for why I did something is rather freeing. I can see why Neal Norwitz is on perpetual sabbatical from python-dev.&lt;br /&gt;&lt;br /&gt;But I do miss being plugged in. Having to get my news through &lt;a href="http://twitter.com"&gt;Twitter&lt;/a&gt; about what is going on still feels odd -- this was made especially true when &lt;a href="http://www.python.org/dev/peps/pep-0383/"&gt;PEP 383&lt;/a&gt; was accepted and I didn't even know the PEP existed until people tweeted about the acceptance.&lt;br /&gt;&lt;br /&gt;And I still think about my long-standing projects. I am thinking about how to handle the &lt;a href="http://www.selenic.com/mercurial/wiki/"&gt;Mercurial&lt;/a&gt; transition and what workflow we should end up with. I still think about what I might need to implement in C for &lt;a href="http://docs.python.org/dev/py3k/library/importlib.html"&gt;importlib&lt;/a&gt; in order to prevent people from lynching me when I bootstrap it in at the implementation of import. This means that once I am done defending my thesis proposal I will be coming back to python-dev.&lt;br /&gt;&lt;br /&gt;But I suspect I won't rejoin every mailing list I disabled delivery for. And I also expect I will be much quicker on telling people to move over to &lt;a href="http://mail.python.org/mailman/listinfo/python-ideas"&gt;python-ideas&lt;/a&gt; along with very liberally using the &lt;a href="http://mail.google.com/support/bin/answer.py?hl=en&amp;amp;answer=47787"&gt;muting feature in Gmail&lt;/a&gt;. I have had a taste of freedom from senseless arguments and whining and I don't plan to go back to it without a fight.&lt;br /&gt;&lt;br /&gt;One month down, two more to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7879848734023692755?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/7879848734023692755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/05/month-one-of-my-python-dev-sabbatical.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7879848734023692755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7879848734023692755'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/05/month-one-of-my-python-dev-sabbatical.html' title='Month one of my python-dev sabbatical'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-1889649710855387307</id><published>2009-05-04T14:34:00.003-07:00</published><updated>2009-05-04T14:46:31.178-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web development'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Does XHR lead to better testing/abstraction?</title><content type='html'>I was talking with a friend of mine who is a Ruby programmer who does Rails development and I asked her how best to handle a form submission that was malformed. I am thinking of the situation when I have a URL that accepts a POST from a web page and some argument is in the wrong format or an argument is entirely missing. I wanted some way to signal the POST submission was bad directly from the HTTP status code or something. I mean you should have some clear way to know that something failed along with a message as to why it failed.&lt;br /&gt;&lt;br /&gt;But she said it should return a 200 with response page specifying what went wrong. When she said that my &lt;acronym title="test-driven development"&gt;TDD&lt;/acronym&gt; sensibilities along with my separation of concerns training recoiled in horror. To test the URL response I have to parse the HTML for error output?!? That means I have to inspect the view to know that an error occurred! And this is simply not testing the view to make sure an error was made visible to the user, this was to test the error was caught, period.&lt;br /&gt;&lt;br /&gt;After I recovered from my shock at this suggested practiced and realized most sites worked like this I realized why it offended me so much. Just like everyone else I was taught that &lt;acronym title="Model-View-Controller"&gt;MVC&lt;/acronym&gt; was generally the best way to structure GUI applications, and in general I agree with the assessment. In my opinion an application should function regardless of what the GUI iss, making the front-end a separate component of the overall application. One should be able to swap out the "V" from MVC and have things still work. That's just good abstraction in my opinion. That means I should be able to test the core components of an application -- the M and C -- without a GUI. And yet with most web apps we do not get this separation thanks to most forms signaling a failure based on what is displayed in the reply.&lt;br /&gt;&lt;br /&gt;With this in mind I began to think about how I could rectify this situation for my web app I was developing. And that's when I realized that using &lt;abbr title="xmlHttpRequest"&gt;XHR&lt;/abbr&gt; to send a form's data to a URL and use the response to handle errors was, from a testing perspective, the best way to go. It might make the client-side code more complicated as a click in a form would no longer simply be the case of the web browser redirecting to a specific page but require processing a response -- probably &lt;a href="http://www.json.org/"&gt;JSON&lt;/a&gt; -- and handling the reply. But from a testing perspective I would be able to test the submission URL in isolation from the web page, thus separating the V from the M and C. Plus it would give me a REST API upfront and thus not require me to create it later -- if I chose to document the API and make it public.&lt;br /&gt;&lt;br /&gt;That's when I said to myself, "OK, so how does everyone else handle signifying an error when it comes to errors in a REST API"? And that's when I found out everyone does it there own little way. About the only thing I found that was consistent is that if everything went well the URLs returned a 200 and when it went to hell they returned a 404. But from there there was no consistency. Only looking at JSON responses, some included the HTTP status code in the error message while others did not. Some had the idea of a class of error and a message while others only had a classification. Some had no answer whatsoever (I'm looking at you XML-RPC), and some went over the top (that would be SOAP).&lt;br /&gt;&lt;br /&gt;So I began to wonder about what I would do to signify a failure for a REST call. The first thing I agreed upon was that returning 200/404 was reasonable. It does irk me slightly since it is just like returning 0/1 in C to signal an error, but it works in this situation where one does not have proper exceptions nor other status codes to use to signal different types of errors. I could inspect the returned JSON object for an 'error' attribute to realize an error object was returned, but this works just as well and I would rather dispatch on status code than have to introspect the returned value.&lt;br /&gt;&lt;br /&gt;Having chosen a way to signify an error, I then thought about what the JSON reply would require. I thought about how Python signifies errors and almost went down the road of something like exceptions complete with inheritance. But I quickly realized that would require loading JavaScript code just for defined exceptions and I didn't like that for an exposed API; for a REST API one should be able to just read the API docs to make a call and not require including any special JavaScript code. I also realized that this was an API issue, not a programming issue. I was more interested in how Python handled errors when calling functions than how bad syntax was flagged.&lt;br /&gt;&lt;br /&gt;That means that I wanted something like TypeError when an argument is missing and ValueError when some input is malformed. That's when I figured why can't I just do something like that? If I had a JSON object have an 'error' attribute that specified the type of error, like "TypeError" or "ValueError", I would have my TypeError/ValueError in JSOn. A 'message' attribute would work as &lt;code&gt;BaseException.args[0]&lt;/code&gt;. And then I could tack on arbitrary attributes on this error object for error-specific information such as what argument was missing or what kind of format was expected for a field.&lt;br /&gt;&lt;br /&gt;And so all of this is what I plan to do the next time I have any data that needs to be sent to a URL for something that is public-facing and and not a hack (although honestly, isn't everything  hack and we just happen to be willing to chance having the public use it?). Yes, it complicates the client-side stuff, but actually the JS code could be made into a library to nicely flag errors, etc. if one standardized on the type of errors that would be returned. Plus it makes unit testing the controller much easier. And it forces you to have a REST API upfront so you don't have to design it later.&lt;br /&gt;&lt;br /&gt;Oh, and if anyone says, "what about &lt;a href="http://www.w3.org/MarkUp/Forms/"&gt;XForms&lt;/a&gt;?", I will say, "get it in all of the major web browsers and then we can talk".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-1889649710855387307?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/1889649710855387307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/05/does-xhr-lead-to-better.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/1889649710855387307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/1889649710855387307'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/05/does-xhr-lead-to-better.html' title='Does XHR lead to better testing/abstraction?'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-8496407883773069365</id><published>2009-04-28T20:53:00.002-07:00</published><updated>2009-04-28T21:34:44.637-07:00</updated><title type='text'>Designing the model schema for part of my father's web site</title><content type='html'>Since I am still on sabbatical from python-dev and my personal web app is not ready for public consumption or discussion yet I have decided to keep this blog going by talking about the steps I am planning to take to re-implement my father's &lt;a href="http://www.cannonbullock.com/"&gt;business site&lt;/a&gt; from a static &lt;a href="http://www.php.net/"&gt;PHP&lt;/a&gt; site to an &lt;a href="http://code.google.com/appengine/"&gt;App Engine&lt;/a&gt;/&lt;a href="http://www.djangoproject.com"&gt;Django&lt;/a&gt; one (plus hopefully fix it so it no longer reflects its initial conception in the late 1990's).&lt;br /&gt;&lt;br /&gt;The first part of the site I plan to redo is the &lt;a href="http://www.cannonbullock.com/WallCoverings/"&gt;wall coverings&lt;/a&gt; section. Looking purely from a model schema view, the wall coverings fall under one of two baseline paper collections (&lt;a href="http://www.cannonbullock.com/WallCoverings/ChinaWall/index.html"&gt;China Wall&lt;/a&gt; and &lt;a href="http://www.cannonbullock.com/WallCoverings/Caravan/index.html"&gt;Caravan&lt;/a&gt;). Here is how I see the model for the collections looking (I am using shorthand here but it should be obvious how this will translate into an App Engine model definition).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;BaseCollection:&lt;br /&gt;    """A base paper collection (e.g. Caravan and China Wall)."""&lt;br /&gt;    name = String&lt;br /&gt;    one_liner = String&lt;br /&gt;    description = Text&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nothing fancy and covers the basic text needed for the collections. Now within each collection there are color lines and what I call "fancy" lines (i.e. paper lines with more than just color added). For the color lines (e.g. &lt;a href="http://www.cannonbullock.com/WallCoverings/ChinaWall/imperial_scrolls.html"&gt;Imperial Scrolls&lt;/a&gt;), the model is very much like the BaseCollection model.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ColorLine:&lt;br /&gt;    """A color line (e.g. Imperial Scrolls)."""&lt;br /&gt;    base_collection = Reference(BaseCollection)&lt;br /&gt;    name = String&lt;br /&gt;    one_liner = String&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Beyond the reference to &lt;code&gt;BaseCollection&lt;/code&gt; there is really nothing special here. By adding the reference back to &lt;code&gt;BaseCollection&lt;/code&gt; instances of the class will grow a &lt;code&gt;colorline_set&lt;/code&gt; attribute the contains the models that reference that instance.&lt;br /&gt;&lt;br /&gt;But having some text to explain a color line is rather useless without the individual papers that make up a color line.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;PaperColor:&lt;br /&gt;    """A color of paper."""&lt;br /&gt;    name = String&lt;br /&gt;    picture = Blob&lt;br /&gt;    color_line = Reference(ColorLine)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With this model I will be able to store the scanned color samples of the paper and associate them with the proper color line. This will give me a &lt;code&gt;papercolor_set&lt;/code&gt; attribute on &lt;code&gt;ColorLine&lt;/code&gt; instances, making it easy to generate those color swath pages.&lt;br /&gt;&lt;br /&gt;But all of this was the easy stuff. The tricky part is the fancy lines (e.g. &lt;a href="http://www.cannonbullock.com/WallCoverings/ChinaWall/Linea/index.html"&gt;Linea&lt;/a&gt;). For these fancy lines they are associated with a specific color line along with the customization options. Since my father has been in the wall covering business for over a decade and so far every fancy line they have has no more options than patterns and one other custom thing, I think I can handle those cases with three models.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Pattern:&lt;br /&gt;    """A single instance of a pattern for a FancyLine (e.g. a single pattern&lt;br /&gt;    for Linea)."""&lt;br /&gt;    fancy_line = Reference(FancyLine)&lt;br /&gt;    name = String&lt;br /&gt;    picture = Blob&lt;br /&gt;&lt;br /&gt;FancyOption:&lt;br /&gt;    """An option for some paper (e.g. pen ink color)."""&lt;br /&gt;    name = String&lt;br /&gt;    description = Text (?)&lt;br /&gt;    # fancyline_set&lt;br /&gt;    # option_set&lt;br /&gt;&lt;br /&gt;Option:&lt;br /&gt;    """A single option for a FancyOption (e.g. slate pen color)."""&lt;br /&gt;    fancy_option = Reference(FancyOption)&lt;br /&gt;    picture = Blob&lt;br /&gt;    name = String&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Pattern&lt;/code&gt; is an instance of a pattern for a fancy line. Since patterns are not shared I don't think a model to collect the patterns separately from a &lt;code&gt;FancyLine&lt;/code&gt; instance is needed. As for &lt;code&gt;FancyOption&lt;/code&gt;, I made that collecting model since it can be shared between lines (e.g. all the lines that use pens have the same color options since the same set of pens are used). Each option is thus covered by an &lt;code&gt;Option&lt;/code&gt; instance which will store some scanned representation of the option.&lt;br /&gt;&lt;br /&gt;But this is where my rudimentary web site experience ends, and unfortunately there is more to do. I still have to have &lt;a href="http://www.cannonbullock.com/WallCoverings/ChinaWall/Linea/installation_examples.html"&gt;installation examples&lt;/a&gt;. I am thinking of doing a model that takes an upload of a full-size photo and auto-generates the thumbnail upon upload (should be easy with the &lt;a href="http://code.google.com/appengine/docs/python/images/"&gt;images API&lt;/a&gt; from App Engine). Trick is then somehow pulling from these to show up in the sidebar of their respective paper line pages. I am thinking that adding a boolean to the model so that a simple filter for the photos with the boolean set to true will be enough to pull up the preferred installation photos for the main pages.&lt;br /&gt;&lt;br /&gt;I also have to deal with the &lt;a href="http://www.cannonbullock.com/WallCoverings/ChinaWall/flame_spread_report.html"&gt;flame spread reports&lt;/a&gt;. There are only three of them: one for each base paper and one for a specific fancy line. That means dealing with the single outlier. I am tempted to make a model for the reports, have a blob for a PDF, and then having a generic reference in the model to the most generic line it represents. That way I can check if for each line if the instance has a &lt;code&gt;flamespread_set&lt;/code&gt; or whatever with an instance to know whether a special flame spread report exists.&lt;br /&gt;&lt;br /&gt;And then there are installation instructions which are in a similar spot as the flame spread reports.&lt;br /&gt;&lt;br /&gt;I think all of these models cover what I need. Hopefully I have not generalized too much or painted myself in a corner. I don't think any of this will make adding or editing content by my father on his own too difficult (which is the entire reason I am redoing the site), especially if I make sure that the forms to change stuff is dead-simple.&lt;br /&gt;&lt;br /&gt;And if I am doing something silly, please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8496407883773069365?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/8496407883773069365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/04/designing-model-schema-for-part-of-my.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8496407883773069365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8496407883773069365'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/04/designing-model-schema-for-part-of-my.html' title='Designing the model schema for part of my father&apos;s web site'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-5050155025769375324</id><published>2009-04-03T16:44:00.003-07:00</published><updated>2009-04-04T09:49:57.572-07:00</updated><title type='text'>PyCon 2009 recap: Best PyCon ever!</title><content type='html'>I landed in Chicago midday in hopes of catching the tail-end of the &lt;a href="http://us.pycon.org/2009/about/summits/vm"&gt;VM summit&lt;/a&gt;. After grabbing my luggage and finding the shuttle to the hotel idling at the curb -- which took a little to find as the signage pointing you to where the shuttles wait is not good at ORD -- I got to the hotel, checked in, and went on down to the summit. There I found a room with a bunch of VM implementors standing around talking.&lt;br /&gt;&lt;br /&gt;Turns out that the entire summit had been like that. After brief introductions by each team -- including the public unveiling of &lt;a href="http://code.google.com/p/unladen-swallow/"&gt;Unladen Swallow&lt;/a&gt; -- apparently everyone just started chatting in small groups and that continued until people broke up for dinner.&lt;br /&gt;&lt;br /&gt;When I arrived I instantly started chatting with the CPython guys in the back of the room. One of the great things of PyCon is getting to see friends in person that I typically only get to see at the conference. It's one of those situations where you just start talking almost instantly without a huge build-up of what anyone has been up to since we read each other's blogs, IM or Twitter, etc. Chatting went on for several hours as more people began to show up at the hotel. Eventually we stopped for dinner at a place a block away from the hotel, after which I just slept.&lt;br /&gt;&lt;br /&gt;Thursday was the first &lt;a href="http://us.pycon.org/2009/about/summits/language"&gt;Python language summit&lt;/a&gt;. Originally there was going to be a morning session of general discussion followed by a 2.7/3.1 discussion with parallel tracks midday/afternoon, but those plans were scrapped. Instead we ended up all staying in the same room talking all day.&lt;br /&gt;&lt;br /&gt;During the initial session we all just talked about various things. For me it became very obvious that the DVCS was going to be a running topic of interest for the rest of my stay at PyCon. I don't remember anything specific coming up in the first session.&lt;br /&gt;&lt;br /&gt;For the 2.7/3.1 session several things came up. One was that it is very likely 2.7 will be the end of the line for the 2.x series for Python. While the idea was floated of canceling 2.7 entirely, that was disliked and instead the preferred approach of strongly stating the opinion that 2.7 will be the end of 2.x was chosen.&lt;br /&gt;&lt;br /&gt;It was also strongly stated that new features cannot exist only in 2.7. Even more important, though, was that people should strongly consider adding new features only to 3.x in order to help entice people to move to 3.x.&lt;br /&gt;&lt;br /&gt;This discussion segued into the idea of &lt;a href="http://svn.python.org/view/sandbox/trunk/refactor_pkg/"&gt;3to2&lt;/a&gt;. The idea sprung up at PyCon 2008 but never went anywhere other than being an idea. During the summit, though, the various framework implementors said that they would love to get to code in 3.x and then run 3to2 over their code to get 2.x code for their compatibility requirements. Thanks to 3.x having clearer semantics -- clear separation of Unicode and bytes, nicer syntax, etc. -- it is actually easier to go from 3.x to 2.x than the other way around. There was general excitement that this idea could pan out and be a great way to get adoption of 3.x to pick up.&lt;br /&gt;&lt;br /&gt;In terms of Python 3.0 it was decided that 3.0.2 would be the last release. We will not even bother with security fixes for the release as the user-base is so small and 3.1 such a nice step up in performance that it will not be worth our time to maintain even security patches for 3.0. Obviously this is a very unique situation and we are not about to start doing this on a regular basis.&lt;br /&gt;&lt;br /&gt;After lunch was the alternative VM session where we discussed how other VMs -- basically &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt;, &lt;a href="http://www.codeplex.com/IronPython"&gt;IronPython&lt;/a&gt;, and &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/"&gt;PyPy&lt;/a&gt; -- fit into all of this. With Unladen Swallow effectively acting as a long-term branch of CPython the discussion focused around the other VMs and how to put them on equal footing with CPython. My big suggestion, which was surprisingly well-received, was to pull out the part of the standard library implemented in pure Python, all of the tests for things that all VMs are expected to implement, and the documentation and place it all as a top-level project within CPython's code repository. The idea would be for all VMs, including CPython, to pull in the standard library from this project along with the tests they are expected to pass. That way we can pool development resources on the standard library along with making sure the test suite properly reflects what a Python VM must pass to be called a true implementation of Python. The versions of the language will still be tied to CPython but at least the language will seem to be less of "what CPython does" and more "what the test suite and standard library say it is". And to help facilitate this the various major contributors to the VMs have been given commit privileges to help start cleaning up the test suite. This should start to happen once we switch over to Mercurial.&lt;br /&gt;&lt;br /&gt;The last session of the day was on packaging. The general consensus of that session is that distutils needs to be cleaned up and morph into a support library that third-party tools can be built off of. So tools like &lt;a href="http://pypi.python.org/pypi/virtualenv"&gt;virtualenv&lt;/a&gt; or &lt;a href="http://www.buildout.org/"&gt;buildout&lt;/a&gt; won't go away and be replaced by distutils, but they should be able to harness more of distutils to have a more common base. It also looks like an extensible, declarative format is going to be developed for those situations where a setup.py script is overkill. Tarek is spearheading this endeavor and hopefully he will be enough of a dictator to make sure it happens.&lt;br /&gt;&lt;br /&gt;Friday was the first day of the conference where I got to give the first &lt;a href="http://pycon.blip.tv/file/1947231/"&gt;lightning talk on why Git was no longer being considered&lt;/a&gt; in the morning (I start at 3:47 in the video). I also had my talk on &lt;a href="http://pycon.blip.tv/file/1947394/"&gt;how Python is developed&lt;/a&gt; along with the &lt;a href="http://pycon.blip.tv/file/1947197/"&gt;Python VM panel&lt;/a&gt;. I also somehow got pulled into giving my shorter-than-I-remembered intro talk on sprinting on Sunday along with a tutorial on how to contribute to Python.&lt;br /&gt;&lt;br /&gt;As per usual for me at PyCon I missed most of the talks at the conference. The ones that I saw which have videos online as I write this are for &lt;a href="http://pycon.blip.tv/file/1952623/"&gt;Pinax&lt;/a&gt;, &lt;a href="http://pycon.blip.tv/file/1949619/"&gt;IronPython implementation&lt;/a&gt;, &lt;a href="http://pycon.blip.tv/file/1947387/"&gt;IronPython status update&lt;/a&gt;, &lt;a href="http://pycon.blip.tv/file/1947354/"&gt;intro to multiprocessing&lt;/a&gt;, and &lt;a href="http://pycon.blip.tv/file/1947511/"&gt;concurrency and distributed computing in Python&lt;/a&gt;. All of those talks were entertaining and are worth watching if you are interested in the subject matter. Otherwise I just attended all of the lightning talks and the keynotes -- the one thing of interest during the keynotes was Guido's talk when he said he was "tiring" but not "retiring".&lt;br /&gt;&lt;br /&gt;In terms of ancillary activities during the conference I had the usual &lt;a href="http://www.python.org/psf/"&gt;Python Software Foundation&lt;/a&gt; stuff to deal with. We elected a lot of new members along with expanding the &lt;a href="http://www.python.org/psf/records/board/"&gt;board&lt;/a&gt; to ten people -- I am still on it -- and keeping the trademark of the Python logo.&lt;br /&gt;&lt;br /&gt;I also was the co-conspirator of the "&lt;a href="http://lindbergd.info/"&gt;VAN LINDBERG'D&lt;/a&gt;" catch-phrase. &lt;a href="http://jessenoller.com/"&gt;Jesse Noller&lt;/a&gt; was my roommate and we were up late one night and somehow we were saying we wished we could force the idiots online who put time and effort into trash-talking Python and spend that time instead attempting to contribute to help fix the situation they were unhappy with. Somehow we thought about changing the Python software license such that if you complained without helping we would send &lt;a href="http://www.haynesandboone.com/Van_Lindberg/"&gt;Van Lindberg&lt;/a&gt;, the PSF lawyer, after you and take you down. We dubbed it being "VAN LINDBERG'D" and it led to &lt;a href="http://lindbergd.info/"&gt;lindbergd.info&lt;/a&gt; and &lt;a href="http://blip.tv/file/1931026"&gt;Jesse's very entertaining lightning talk&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Then came the sprints. The core, as usual, had a good turn-out. This year, though, I at least was able to tell people to work on tests to raise test coverage if they didn't have anything to work on. Having the new developer docs that I have written helped a lot since I finally had something concrete to point people to in order to get up and running.&lt;br /&gt;&lt;br /&gt;I personally had no agenda beyond try to help people where needed and to clear out my backlog of issues (which I actually did in the end). Various people worked on things and last I heard from &lt;a href="http://pyside.blogspot.com/"&gt;Georg Brandl&lt;/a&gt; we had closed over 125 bugs Wednesday night, of which just under half were closed by Georg himself.&lt;br /&gt;&lt;br /&gt;But the great thing that happened during the sprints was not the coding but the camaraderie that broke out amongst &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; and &lt;a href="http://pinaxproject.com/"&gt;Pinax&lt;/a&gt; Tuesday. The core team was next door to the Pinax sprint room and at some point on Tuesday we heard some laughing continually break out. Turns out a little "war" had broken out between the Django and Pinax teams, culminating in several domains being purchased and the Django pony being made to do things no stuffed animal should have to do. Eventually there was a peace accord. &lt;a href="http://jtauber.com/"&gt;James Tauber&lt;/a&gt; plans to write up a blog post about what happened so I will let him tell the story. For the core's part some of us got pulled into all of it, leading to &lt;a href="http://ponysex.us/"&gt;ponysex.us&lt;/a&gt; coming into existence (the site is Safe For Work).&lt;br /&gt;&lt;br /&gt;The night that ponysex.us came into existence was also the night before April Fool's. The idea for the Python April Fool's for this year took a couple of turns before it ended up at what was posted online. I originally came up with the idea of doing a blog post where I helped lead a coup against Guido to usurp him as dictator and install Barry Warsaw as my puppet with a future statement for adding back in the diamond operator to massage Barry's ego to help keep him in line. I had that idea nearly a year ago and told Guido about it during my internship. He liked it so I did the future statement on the flight to PyCon and let Barry in on the idea at the conference.&lt;br /&gt;&lt;br /&gt;That's when Barry decided he wanted to tweak it. Because of Guido's whole "not retiring, just tiring" bit in his keynote, Barry wrote up &lt;a href="http://www.blogger.com/www.python.org/dev/peps/pep-0401/"&gt;PEP 401&lt;/a&gt;, suggesting Guido was retiring and would be replaced by Uncle Tim. That made the use of the diamond operator not quite as poignant as Tim has never expressed a dislike for '!=' while Barry and Thomas Wouters have both stated that they preferred '&lt;&gt;', but it still would be funny.&lt;br /&gt;&lt;br /&gt;Then Guido decided to tweak it to have Barry be the successor and throw in the idea of Barry switching us to Bazaar instead of Mercurial. I am sure getting back his precious diamond operator in Python 3.1 has made up for any possible disappointment from Mercurial being chosen over Bazaar for Barry.&lt;br /&gt;&lt;br /&gt;And then there was Wednesday night. At some point the Django folks relocated to the Pinax sprinting room. Since there were not that many core sprinters at the time, we decided to relocate to the room where the laughter was coming from. After sitting down, one of the core developers, who will remain nameless to prevent embarrassment with any potential future employers, seemed determine to get his drink on -- a lot of us were happy to join in of course. Eventually some people went out and bought some liquor, which led to the core team finishing off a bottle of Knob Creek and a little bit of scotch -- most of it was drunk by one individual and myself. I actually managed to check in code that night, although there was an unfortunate svnmerge mishap that deleted the metadata for the tool. But otherwise it was a fun night of drinking and joking all around (read Twitter of the folks attending to get an idea of what the heck was going on).&lt;br /&gt;&lt;br /&gt;In the end &lt;a href="http://us.pycon.org/2009/about/"&gt;PyCon 2009&lt;/a&gt; turned out to be the best PyCon I have attended. The language summit was fun and seemed to produce some results. I got in a great amount of socializing during the conference. And the sprints were just awesome. PyCon 2010 in Atlanta has a lot to live up to for me personally.&lt;br /&gt;&lt;br /&gt;I should also probably mention I am going to take three months off from Python development in order to focus on my thesis proposal which is due by July 1. It will also give me a chance to finally redo my &lt;a href="http://www.cannonbullock.com/"&gt;father's web site&lt;/a&gt; in Django -- maybe even Pinax -- so that he can update the information on the site himself in a manner easy enough that even his partner could do it -- he just learned about copy and paste, although he can navigate the web fine -- while leaving me in complete control of layout. In other words this blog's focus will be shifting for the near term to web programming stuff and I might be suffering from Python withdrawl.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-5050155025769375324?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/5050155025769375324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/04/pycon-2009-recap-best-pycon-ever.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5050155025769375324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5050155025769375324'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/04/pycon-2009-recap-best-pycon-ever.html' title='PyCon 2009 recap: Best PyCon ever!'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-7511529311823937231</id><published>2009-04-01T00:01:00.000-07:00</published><updated>2009-04-01T07:57:06.921-07:00</updated><title type='text'>Guido has retired as BDFL</title><content type='html'>&lt;a href="http://www.python.org/dev/peps/pep-0401/"&gt;PEP 401&lt;/a&gt; says it all: Guido has retired. If you attended PyCon you heard Guido's keynote where he mentioned he was tired but not retiring. Well, "tired" turned to "retired" rather quickly once the sprints started.&lt;br /&gt;&lt;br /&gt;To replace him as BDFL is Barry Warsaw, Friendly Language Uncle For Life (FLUFL). Read the PEP for details, but the things on the FLUFL's agenda is:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Switch to bzr over hg.&lt;/li&gt;&lt;li&gt;Move to '&lt;&gt;' over '!='.&lt;/li&gt;&lt;li&gt;Back to 'print' as a statement.&lt;/li&gt;&lt;li&gt;Shut down 3.x and backport everything to 2.7.&lt;/li&gt;&lt;li&gt;Move over to Parrot as the VM for Python.&lt;/li&gt;&lt;li&gt;Disband the PSF.&lt;/li&gt;&lt;/ul&gt;To help with the transition I have implemented a new future statement to make the diamond operator -- '&lt;&gt;' -- the one true way to write NOTEQUAL over '!=':&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;from __future__ import barry_as_FLUFL&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This has been checked into Python 3.1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7511529311823937231?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/7511529311823937231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/guido-has-retired-as-bdfl.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7511529311823937231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7511529311823937231'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/guido-has-retired-as-bdfl.html' title='Guido has retired as BDFL'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-2653508241950466912</id><published>2009-03-31T11:59:00.003-07:00</published><updated>2009-03-31T14:10:04.159-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='version control'/><title type='text'>Why Python is switching to Mercurial</title><content type='html'>Starting at PyCon 2008 thanks to Barry Warsaw and the Bazaar team I started thinking about moving Python over to a distributed version control system (DVCS). While I wanted to get offline commits for the benefit of non-core developers along with easier merging from 2.6 to 3.0 (ah, the days when there are only three branches under development), I knew that would not necessarily be enough of a reason for others to switch.&lt;br /&gt;&lt;br /&gt;Come October I started a PEP for switching off of svn to a DVCS. Originally it was going to be hg vs. bzr, but enough of an outcry on python-dev led to me to relent to adding git to the PEP. With the list of DVCSs decided I began writing up common use cases that I and other developers have come up against in developing Python. I then had a representative for each DVCS fill in the PEP with the best solution to the use case (who I am grateful to for helping). This all became &lt;a href="http://www.python.org/dev/peps/pep-0374/"&gt;PEP 374&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And for me that's when the stress began. I was being bombarded on all sides on this pretty regularly. I quickly realized that choosing a DVCS was like choosing a code editor; it's a very personal thing for a lot of people. Plus I forget how big Python is now; when what I was doing hit the Net I ended up talking with developers from all three DVCSs which I didn't expect.&lt;br /&gt;&lt;br /&gt;Time past and I tried to absorb all three DVCSs as much as I could, although with my internship and trying to finish importlib for 3.1 I only had so much time. I ran a survey of the core developers where I asked them to rate the three DVCSs as either better, equal, or worse than svn if they felt they had enough experience to have an opinion.&lt;br /&gt;&lt;br /&gt;Based on the results of that survey where git was clearly the most disliked tool of the core developers, having the weakest Windows support, and not being implemented in Python, I decided to eliminate git from the running and announce its elimination at the first lightning talk at PyCon.&lt;br /&gt;&lt;br /&gt;When I arrived at PyCon pretty much everyone asked me about the DVCS PEP. People wanted to know how it was going, who was going to win, and giving me support/pity for what I was going through. Guido noticed this and decided to end my misery by saying he wanted to make a decision by the end of PyCon. I said I was fine with that as one was already about to be eliminated and I knew my personal preference at that exact moment aligned with Guido's.&lt;br /&gt;&lt;br /&gt;So I did my lightning talk eliminating git. Luckily that went well with only about two people telling me directly they disliked the decision.&lt;br /&gt;&lt;br /&gt;But the more telling thing was what everyone else told me after that lightning talk. I ended up with a surprisingly large number of people telling me -- including core developers -- they wanted, preferred, or guessed that hg would now win. Now the guesses could be explained away by Guido having publicly stated he likes hg, but to me the amount of people telling me they wanted hg to be chosen was surprisingly large. And honestly no one told me they preferred bzr (although no one said I better choose hg over bzr either).&lt;br /&gt;&lt;br /&gt;So Monday morning came around and I walked into the sprint. I asked Guido if he was ready to make a decision. He said yes, we both said hg, and so Guido &lt;a href="http://twitter.com/gvanrossum/status/1418085336"&gt;tweeted the decision&lt;/a&gt; before &lt;a href="http://mail.python.org/pipermail/python-dev/2009-March/087931.html"&gt;telling python-dev&lt;/a&gt; that we chose Mercurial.&lt;br /&gt;&lt;br /&gt;There has been a lot of speculation as to why Guido pronounced the way he did. On Twitter Guido said to read PEP 374 for the reasons. Since I helped write my PEP my reasons are reflected in the PEP.&lt;br /&gt;&lt;br /&gt;Obviously community preference as shown at PyCon played a role. No one wants to choose a DVCS that causes the community to not want to contribute to Python. And I would never choose a VCS that would cause Guido to not want to work on Python. Some people seem surprised that something non-technical played a role, but ignoring social issues is to ignore how much open source is a social phenomenon. And we are not the first project to take social preference into consideration: I know both GNOME and Pinax chose git because their developers preferred git.&lt;br /&gt;&lt;br /&gt;And there are technical reasons. Having hg being faster than bzr by 2x to 3x does matter to some extent. No one wants to cause someone to not contribute because they didn't want to wait for a checkout. And having personally experienced long checkout times because of a subpar connection to a specific server I know this can occur. The performance margin between hg and bzr is within reason typically and is not a flat-out deal-breaker, but it doesn't help either.&lt;br /&gt;&lt;br /&gt;Bazaar also has its short timespan of format stability working against it. The tool has changed its format at least three times based on what the man page says (1.0, 1.6, and 1.9). Mercurial, on the other hand, has been stable since I think it went public or near that time. They take great pride in the fact they have not changed it. And that stability more aligns with python-dev's sensibilities regarding stability.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://lists.ubuntu.com/archives/bazaar/2009q1/055872.html"&gt;Stephen Turnbull's explanation&lt;/a&gt; of why on the bzr mailing list is also a good explanation of why we chose hg. Basically no one is saying bzr is bad, just that hg is a better fit for our needs on python-dev.&lt;br /&gt;&lt;br /&gt;But the thing I really love about having made this decision -- other than I don't have to stress about this anymore -- is that everyone seems to be flat-out happy we made a decision to switch as well. Once again the Python community stands out as being friendly and understanding about stuff like this with no one really seeming to be upset that we made the decision we did.&lt;br /&gt;&lt;br /&gt;As for when the switch will happen, I don't know. We are hoping by summer, but that is just a hope at the moment. We have to figure out the best way to convert our history as well as what workflow we want to have.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-2653508241950466912?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/2653508241950466912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/why-python-is-switching-to-mercurial.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/2653508241950466912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/2653508241950466912'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/why-python-is-switching-to-mercurial.html' title='Why Python is switching to Mercurial'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-765418717510817499</id><published>2009-03-19T15:34:00.002-07:00</published><updated>2009-03-19T15:38:51.406-07:00</updated><title type='text'>Consider volunteering at PyCon</title><content type='html'>Doug has sent out a &lt;a href="http://www.dougma.com/archives/155"&gt;request for help at PyCon&lt;/a&gt;. If you will be attending PyCon and are willing to help, please do! PyCon is volunteer-driven so we need all the volunteers we can get.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-765418717510817499?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/765418717510817499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/consider-volunteering-at-pycon.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/765418717510817499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/765418717510817499'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/consider-volunteering-at-pycon.html' title='Consider volunteering at PyCon'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-1916938738713513738</id><published>2009-03-18T13:23:00.001-07:00</published><updated>2009-03-18T13:25:12.857-07:00</updated><title type='text'>Last day for online registration to PyCon</title><content type='html'>Helping to spread the word that &lt;a href="http://pycon.blogspot.com/2009/03/last-day-for-online-registration.html"&gt;today is the last day to register&lt;/a&gt; for PyCon online. You can still register at the door, although obviously it is a little bit more expensive.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-1916938738713513738?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/1916938738713513738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/last-day-for-online-registration-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/1916938738713513738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/1916938738713513738'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/last-day-for-online-registration-to.html' title='Last day for online registration to PyCon'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-5753249380090682288</id><published>2009-03-16T19:14:00.004-07:00</published><updated>2009-03-16T22:43:44.339-07:00</updated><title type='text'>Use XMPP for microblogging?</title><content type='html'>I had something interesting happen to me today: people noticed my status message on Google Talk. Normally I figure no one really pays attention to status messages for IM beyond whether someone is online or not (we all know people who are always listed as away or have not changed their status message in ages). But for some reason today I decided to use my status message to bitch about the car issues I was having.&lt;br /&gt;&lt;br /&gt;And people responded. I had various friends IM me throughout the day inquire about what was going on (short answer: transmission is shot and the repair bill is more than the value of the car, so I am trying to get the car recycled; not easy when you drove down to visit a parent in another country). It reminded me of what can happen when &lt;a href="http://twitter.com/brettsky"&gt;I post to Twitter&lt;/a&gt; or &lt;a href="http://friendfeed.com/brettsky"&gt;FriendFeed&lt;/a&gt; when I get to have a topical conversation about what is going on in my life that exact second; instantaneous blogging in snippet form. And it was nice to get to have a conversation with some friends about what was happening. That's something I don't necessarily get to have on Twitter since the threading of the conversation gets all out of whack. And unlike FriendFeed the conversations were private and happening in real-time.&lt;br /&gt;&lt;br /&gt;But the other nice thing is that these conversations were with people I normally don't get to interact with on a regular basis online. Typically I interact with people online through FriendFeed, Twitter, and Google Reader. IM has a much broader reach than any of these newfangled services have.&lt;br /&gt;&lt;br /&gt;For me, the difference between the former services and IM is one takes more proactive participation while the latter is usually only for when I have a specific need or desire to talk with someone. If the people I follow on FF or Twitter post something I will eventually see it when I actively check the application (although obviously you can use notifiers so that the engagement is passively triggered). But with IM, it is typically relegated to the background, sitting there until either I initiate a conversation with someone or vice-versa.&lt;br /&gt;&lt;br /&gt;And yet today that didn't happen. It makes sense that ones status in the world at any moment be tied to their IM persona. I mean my status of being online or not is listed in IM, why shouldn't what I am thinking about or reading also be displayed? We talk about microblogging and lifestreaming services, and yet the one service we all use that portrays our status online is not doing more than showing a green, red, or gray dot next to some picture. It feels like an unneeded disconnect to me that my IM persona does not tie into what else I might share with the world at that moment.&lt;br /&gt;&lt;br /&gt;There is also a case that IM is a better model for microblogging/lifestreaming. It's very much a push model; I decide to say something to the world, it gets pushed to the people who care to listen. And yet all of these other services use a pull model to get the information. Why should my Twitter client have to refresh to find out that there is something new to read? Can't it just be pushed to me? Can't the pull from a web site be a side-effect of providing access while the actual system is push?&lt;br /&gt;&lt;br /&gt;If you listen to &lt;a href="http://www.twit.tv/floss49"&gt;FLOSS Weekly episode 49&lt;/a&gt; you will hear &lt;a href="https://stpeter.im/"&gt;Peter Saint-Andre&lt;/a&gt; mention how he thinks &lt;a href="http://xmpp.org/"&gt;XMPP&lt;/a&gt; is a good system to use for microblogging. I personally buy his arguments. Apparently I am not the only one as people have &lt;a href="http://metajack.im/2008/09/10/xmpp-microblogging-thoughts/"&gt;blogged&lt;/a&gt; about this &lt;a href="http://metajack.im/2008/09/15/an_xmpp_microblogging_stack/"&gt;idea&lt;/a&gt; and gone as far as to sketch out a proposal of &lt;a href="http://xmpp.org/extensions/inbox/microblogging.html#intro"&gt;microblogging over XMPP&lt;/a&gt;. But what exactly would microblogging tied to IM act like?&lt;br /&gt;&lt;br /&gt;First thing first, though, is to realize how microblogging versus IM is different. For one, anyone can follow me on Twitter or FF but not on IM. If some stranger wants to follow me on FF that's fine, but I don't necessarily care when they are online or want to have a personal conversation with them. So any microblogging service would need to make the idea of subscribing to one's microblog feed separate from getting to interact with them directly over IM.  Another difference is the temporal nature of IM status messages versus microblogging. When I change my IM status, that last one vanished into the digital ether. But for microblogging, I don't necessarily want that to happen. So a ticker would be needed to keep track of the messages that have happened throughout the day that I may have missed.&lt;br /&gt;&lt;br /&gt;So what are the benefit of tying microblogging to IM? For one, I could easily respond directly to someone about something and have a truly real-time conversation with them about it. Yes, Twitter has direct messages, but the fluidity of an IM conversation, I feel, is much better. It also simplies things by not forcing me to run yet another service.&lt;br /&gt;&lt;br /&gt;Jaiku actually tried this approach somewhat. While being a lifestreaming app, they also had their S60 client which updated your online status and your location in the world. But I don't think it included IM services which would have been nice.&lt;br /&gt;&lt;br /&gt;Or maybe all I really want is better support for longer IM status messages. What I honestly get out of Twitter is what people are currently up to and some conversations. If longer status messages could easily be displayed and a public group chat around my status message could take place that would be close to what I get out of Twitter with the only thing missing is people overhearing my public conversation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-5753249380090682288?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/5753249380090682288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/use-xmpp-for-microblogging.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5753249380090682288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5753249380090682288'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/use-xmpp-for-microblogging.html' title='Use XMPP for microblogging?'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-6557923717494190339</id><published>2009-03-15T10:20:00.003-07:00</published><updated>2009-03-15T10:28:16.097-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PyCon'/><title type='text'>Google Moderator pages for PyCon VM panel</title><content type='html'>I organized a &lt;a href="http://us.pycon.org/2009/conference/schedule/event/21/"&gt;VM panel at PyCon&lt;/a&gt; this year where a representative from each of the major VMs (CPython, Jython, IronPython, and PyPy) will be in one room to answer your various questions. To help get questions from people who cannot attend along with making our esteem MC's job easier, Jacob (who is the moderator) and I have set up a &lt;a href="http://moderator.appspot.com/#15/e=2fa6a&amp;amp;t=31181"&gt;Google Moderator page for the panel&lt;/a&gt; to propose qauestions.&lt;br /&gt;&lt;br /&gt;Please propose questions or vote questions up and down so that Jacob can come with a battery of questions for the panel to fill in lulls during the Q&amp;amp;A. And I think all talks are being recorded this year so the panel should eventually end up online.&lt;br /&gt;&lt;br /&gt;Oh, and if you are not attending PyCon, you still have a chance to &lt;a href="http://us.pycon.org/2009/registration/"&gt;register&lt;/a&gt; and come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-6557923717494190339?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/6557923717494190339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/google-moderator-pages-for-pycon-vm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/6557923717494190339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/6557923717494190339'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/google-moderator-pages-for-pycon-vm.html' title='Google Moderator pages for PyCon VM panel'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-8593009827744794184</id><published>2009-03-11T16:58:00.004-07:00</published><updated>2009-03-11T17:23:35.595-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python-dev'/><title type='text'>Time deltas between Python releases</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chart.apis.google.com/chart?&amp;amp;chtt=Python+release+time+deltas&amp;amp;chs=1000x300&amp;amp;cht=bhs&amp;amp;chco=000000,262626,4C4C4C,727272,989898,BEBEBE&amp;amp;chdl=x.y.0%7Cx.y.1%7Cx.y.2%7Cx.y.3%7Cx.y.4%7Cx.y.5&amp;amp;chds=0,1484&amp;amp;chxt=y,x&amp;amp;chxl=0:%7C2.6%7C2.5%7C2.4%7C2.3%7C2.2%7C2.1%7C&amp;amp;chxr=1,0,1484,365&amp;amp;chd=t:183,248,585,490,655,746%7C94,110,56,120,214,64%7C180,187,10,182,309,0%7C82,228,77,179,302,0%7C0,0,160,206,4,0%7C0,0,257,0,0,0"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 1000px; height: 300px;" src="http://chart.apis.google.com/chart?&amp;amp;chtt=Python+release+time+deltas&amp;amp;chs=1000x300&amp;amp;cht=bhs&amp;amp;chco=000000,262626,4C4C4C,727272,989898,BEBEBE&amp;amp;chdl=x.y.0%7Cx.y.1%7Cx.y.2%7Cx.y.3%7Cx.y.4%7Cx.y.5&amp;amp;chds=0,1484&amp;amp;chxt=y,x&amp;amp;chxl=0:%7C2.6%7C2.5%7C2.4%7C2.3%7C2.2%7C2.1%7C&amp;amp;chxr=1,0,1484,365&amp;amp;chd=t:183,248,585,490,655,746%7C94,110,56,120,214,64%7C180,187,10,182,309,0%7C82,228,77,179,302,0%7C0,0,160,206,4,0%7C0,0,257,0,0,0" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I have been thinking about what needs to be covered during my session at the &lt;a href="http://us.pycon.org/2009/about/summits/language/"&gt;language summit at PyCon&lt;/a&gt; which will cover 2.7/3.2 issues. One thing I have been wondering about is whether Python should consider shifting to a time-based release schedule. The rule of thumb has been that we do a minor release (e.g 2.7 is the next minor release for on the 2.x series) every 18 months.&lt;br /&gt;&lt;br /&gt;To see if that 18 month idea was true, I created a chart (thanks to the &lt;a href="http://code.google.com/apis/chart/"&gt;Google Chart API&lt;/a&gt; for existing and &lt;a href="http://www.dougma.com/"&gt;Doug Napoleone&lt;/a&gt; for always hyping up the API). The x-axis is number of days and each section of the graph is the length of time to develop a micro release, although developing x.y.0 starts from the release of x.y-1.0 so that's why the initial values are so large.&lt;br /&gt;&lt;br /&gt;It would seem that we are trending away from 18 months between minor releases rather quickly. While I would never propose a hard deadline (that's just stupid for open source when you are not trying to get a packaged piece of software done by a specific date for shipment), I wouldn't mind planning out release dates after the last minor release went out so we know when exactly stuff needs to get out (minus any bumps; see Python 3.1 and its planned 6 month release cycle).&lt;br /&gt;&lt;br /&gt;The chart also points out some interesting things. One is that 2.3 was a trouble-maker. =) It has the most micro releases (2.30 through 2.3.5) on top of having the shortest amount of time between micro releases (10 days between 2.3.1 and 2.3.2 thanks to a bug). The 2.5 branch has been actively maintained the longest (4 years, 24 days from 2.4.0 to 2.5.4). And a random fact for myself: 2.2.3 was the first release which occurred while I had commit privileges.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8593009827744794184?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/8593009827744794184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/time-deltas-between-python-releases.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8593009827744794184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8593009827744794184'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/time-deltas-between-python-releases.html' title='Time deltas between Python releases'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-4057233569164237981</id><published>2009-03-09T14:02:00.028-07:00</published><updated>2009-03-17T11:48:42.612-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jvm'/><title type='text'>Interacting between &lt;insert JVM lang here&gt; and Java</title><content type='html'>[2009-03-15: This blog post has been thoroughly rewritten after I found out some details were wrong and people wanted more details]&lt;br /&gt;&lt;br /&gt;I don't like Java. If care to find out why you can search my blog, but it's no secret Java is not exactly at the top of my list of favorite programming languages. But I am not stupid enough to think that Java is about to go away. And I have nothing against the JVM, just the primary language that runs on it.&lt;br /&gt;&lt;br /&gt;Thanks to the JVM, just because I have to work with Java code does not mean I have to &lt;span style="font-style: italic;"&gt;write&lt;/span&gt; Java code. Thanks to various languages being ported to the JVM there are now multiple options for working with Java code in languages other than Java:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt; - port of &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; - port of &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt; - port of &lt;a href="http://www.ecmascript.org/"&gt;ECMAScript&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt; - Lisp dialect.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; - Scripting language for the JVM.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; - object-oriented, functional language for the JVM.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;By targeting the JVM all the above languages can call Java code in order to be relevant in a Java-heavy world. But just because they can easily consume Java code does not mean that the reverse is true. What I am looking for is not just a way to call &lt;span style="font-style: italic;"&gt;into&lt;/span&gt; Java, but to call other languages &lt;span style="font-style: italic;"&gt;from&lt;/span&gt; Java.&lt;br /&gt;&lt;br /&gt;To better explain this, take the following three files. First, I have Spam.java:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Spam {&lt;br /&gt; public String serves() {&lt;br /&gt;   return "spam";&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I have another class that implements a subclass, BaconSpam.java:&lt;br /&gt;&lt;pre&gt;public class BaconSpam extends Spam {&lt;br /&gt; @Override&lt;br /&gt; public String serves() {&lt;br /&gt;    return "bacon " + super.serves();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;And finally, the class that runs the show, Waitress.java:&lt;br /&gt;&lt;pre&gt;public class Waitress {&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;   BaconSpam menu = new BaconSpam();&lt;br /&gt;   String food = menu.serves();&lt;br /&gt;   System.out.println("We serve " + food + "!");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;What I am after is a language to rewrite BaconSpam.java in another JVM language such that I don't touch Spam.java. I also want the changes to Waitress.java to be minimal or non-existent while still having to store an instance of the class and the value returned by serves() to show how objects would be stored and used in a long-running Java application (i.e. no cheating by inlining some call in the println() call to make the example a little tougher and more "real world").&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Jython&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Thanks to the Jython guys I was pointed to a &lt;a href="http://wiki.python.org/jython/JythonMonthly/Articles/October2006/3"&gt;Jython Monthly article from October 2006&lt;/a&gt; that explains how best to go about accessing Jython code from Java.&lt;br /&gt;&lt;br /&gt;To start I wrote BaconSpam in Python:&lt;br /&gt;&lt;pre&gt;import Spam&lt;br /&gt;&lt;br /&gt;class BaconSpam(Spam):&lt;br /&gt; def serves(self):&lt;br /&gt;   return " ".join(["bacon", Spam.serves(self)])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;While that was rather simple, there is still the issue of getting an instance of the class. Because Jython dynamically interprets Python code you can't simply drop in BaconSpam.py and have it work with Waitress.java. You need to create an instance of org.python.util.PythonInterpreter and interface with it to get at the Python code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import org.python.core.__builtin__;&lt;br /&gt;import org.python.core.PyObject;&lt;br /&gt;&lt;br /&gt;public class Waitress {&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;   PyObject BaconSpam = __builtin__.__import__("BaconSpam").__getattr__("BaconSpam");&lt;br /&gt;   Spam menu = (Spam)BaconSpam.__call__().__tojava__(Spam.class);&lt;br /&gt;   String food = menu.serves();&lt;br /&gt;   System.out.println("We serve " + food + "!");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Because Jython dynamically loads Python code, Waitress.java has to be modified. Luckily a large chunk of the code is boilerplate that can be extracted out into a factory class to help simplify things.&lt;br /&gt;&lt;br /&gt;And just a warning for anyone wanting to run the above code: for some odd reason the above code only worked for me with Jython 2.5b3, not 2.2.1.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;JRuby&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Writing the BaconSpam subclass was simple:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class BaconSpam &amp;lt; Spam&lt;br /&gt;  def serves&lt;br /&gt;    "bacon " + super&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But as of right now you &lt;a href="http://java.sun.com/developer/technicalArticles/scripting/jruby/#ej"&gt;need to use JSR 223&lt;/a&gt; to interface with the class which is worse than the Jython approach, so I am not going to go through the steps here.&lt;br /&gt;&lt;br /&gt;But Charles Nutter has blogged about &lt;a href="http://blog.headius.com/2009/03/more-compiling-ruby-to-java-types.html"&gt;adding signature support to JRuby's in-dev compiler2&lt;/a&gt;. It looks like as soon as inheritance is handled properly in compiler2 that JRuby will be in the same position at Groovy and Scala for ease of integration (see below for details on those two languages).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Rhino&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;I don't like JavaScript, so I am skipping Rhino. =) But it's another JSR 223 approach.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Clojure&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;I actually didn't get Clojure to work. I tried to follow the &lt;a href="http://en.wikibooks.org/wiki/Clojure_Programming/Examples/API_Examples#genclass"&gt;gen-class example&lt;/a&gt; from the Clojure wikibooks, but ran into several issues that included having to manually execute compilation for the Eclipse plug-in to even get an error message and putting the code in a package to get Clojure to not assume I was working off of java.lang when inheriting from Spam.java.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(ns pkg.BaconSpam&lt;br /&gt;(:gen-class&lt;br /&gt; :extends pkg.Spam&lt;br /&gt; :exposes {serves servesSuper}))&lt;br /&gt;&lt;br /&gt;(defn -serves [this]&lt;br /&gt;(str "bacon " (.servesSuper this))&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With an error of "java.lang.IllegalArgumentException: Don't know how to create ISeq from: Symbol", I just stopped trying to make this work. I assume Waitress.java will need to be changed beyond just being put in a package anyway in order to deal with Clojure's dynamic typing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Groovy&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Writing the Groovy version of BaconSpam was very easy thanks to the language having been designed for the JVM from the outset. The only trick was that serves() needed to have the return type specified for the method instead of being dynamic:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class BaconSpam extends Spam {&lt;br /&gt; // Using 'def' makes return value dynamic.&lt;br /&gt; String serves() {&lt;br /&gt;   return "bacon " + super.serves()&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With the typed method there is no need for modifying Waitress.java. Groovy basically ends up looking like Java with some syntax removed.&lt;br /&gt;&lt;br /&gt;One issue that did come up with writing the Groovy example was that the Eclipse plug-in is in some bad shape; I couldn't get it to run the project. This drove me to download and use &lt;a href="http://www.netbeans.org/"&gt;NetBeans&lt;/a&gt; since it has Groovy support included. That was a much better experience since it actually worked.&lt;br /&gt;&lt;br /&gt;Oh, and the docs suck. Took way too long to figure out how the darn language is even structured. Just had to read various examples to figure things out.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Scala&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Much like Groovy, Scala was easy to use to rewrite BaconSpam.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class BaconSpam extends Spam {&lt;br /&gt; override def serves(): String =&lt;br /&gt;   return "bacon " + super.serves()&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And just like Groovy there was no need to change Waitress.java in order to interact with the class. But unlike Groovy the Eclipse plug-in for Scala actually allowed me to execute the application. Plus the docs are better so I didn't have to go digging around to figure out what I needed to do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-4057233569164237981?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/4057233569164237981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/interacting-between-jvm-lang-here-and.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/4057233569164237981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/4057233569164237981'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/interacting-between-jvm-lang-here-and.html' title='Interacting between &amp;lt;insert JVM lang here&amp;gt; and Java'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-5511937360944836369</id><published>2009-03-08T23:20:00.003-07:00</published><updated>2009-03-09T00:52:27.150-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='importlib'/><title type='text'>Importlib is now useful to other people</title><content type='html'>I have always had two goals for importlib. The &lt;a href="http://docs.python.org/dev/py3k/library/importlib.html"&gt;docs for importlib&lt;/a&gt; say they were to provide a reference implementation of import and to make it easier for people to implement their own &lt;a href="http://docs.python.org/dev/py3k/glossary.html#term-importer"&gt;importers&lt;/a&gt;. The former goal is sort of true; the real goal is to not just be a reference implementation of import but to actually become THE implementation of import. The latter goal, though, is spot-on and I finally checked in a big chunk of code tonight that gets me closer to helping other people really harness the flexibility of import.&lt;br /&gt;&lt;br /&gt;The cron job to rebuild the docs has not kicked in yet (I think it runs twice a day), but once it does you will discover there is now a new module: importlib.abc. Within the module there are ABCs for everything specified in &lt;a href="http://www.python.org/dev/peps/pep-0302/"&gt;PEP 302&lt;/a&gt;. Back in January &lt;a href="http://sayspy.blogspot.com/2009/01/confusing-terminology-of-imports.html"&gt;I asked for help&lt;/a&gt; to name those classes. The fruition of that discussion is now finally live.&lt;br /&gt;&lt;br /&gt;But simple ABCs to require load_module exist as a method isn't THAT helpful. What I really wanted to provide was something to make it as easy as possible to write their own custom loaders such that they didn't have to worry about the little details that are consistent between all loaders (and there a lot of details; just look at the "see also" section of the importlib docs). Way back in August 2007 I came up with &lt;a href="http://sayspy.blogspot.com/2007/08/making-it-easier-to-write-custom-code.html"&gt;an idea called handlers&lt;/a&gt; which would deal with stuff like setting __file__, making sure bytecode is recreated when it's older than the source code, etc.&lt;br /&gt;&lt;br /&gt;Unfortunately handlers turned out to be somewhat burdensome. They required a bunch of information upfront to be passed into them that loaders had to provide. On their own they couldn't do much and just became internal delegates for loaders. So I set about trying to come up with a way to merge the handler concept into loaders.&lt;br /&gt;&lt;br /&gt;And it turns out PEP 302 got me part way there. If you look at what it takes to import Python source code (I am ignoring bytecode), you essentially create an empty module, read in the source code, compile the source into a code object, and then execute the code object in the __dict__ of the empty module. After that it's just details like __file__ and such. When you take these basic steps you will notice they roughly align with some APIs that PEP 302 defined as optional protocols loaders could implement. So I asked myself if I could somehow harness the optional protocols to get all the information I need so that I can simply provide a loader that uses those protocols.&lt;br /&gt;&lt;br /&gt;Looking at source only, it would seem like the answer is "yes" since there is a get_source method which obviously returns source code for a module. One would think then an implementation for load_module would simply call get_source, compile it, and then use it to create a module. But of course life is not simple.&lt;br /&gt;&lt;br /&gt;First of all, as I have &lt;a href="http://sayspy.blogspot.com/2009/01/importlib-hits-beta-with-pep-263.html"&gt;discussed before&lt;/a&gt;, reading source from disk was not working for me as I didn't have a simple way to get source from disk in the proper decoding thanks to &lt;a href="http://www.python.org/dev/peps/pep-0263/"&gt;PEP 263&lt;/a&gt;. Everything I came up with was on the complicated side. That meant get_source was not exactly a nice thing to rely upon.&lt;br /&gt;&lt;br /&gt;But the other issue of relying on get_source is it doesn't tell me the path the source came from. That's needed for __file__ to be set. That completely kills solely relying on get_source.&lt;br /&gt;&lt;br /&gt;You could potentially rely on another part of PEP 302 which defines a get_code method which is supposed to return the code object for a module. But that puts more burden on a developer than I wanted to.&lt;br /&gt;&lt;br /&gt;At this point I realized I was probably going to have to add to the APIs that PEP 302 provided. I didn't want to do this as that just makes it that much more difficult to implement a loader, but I realized that the PEP 302 protocols simply did not provide all the information needed to create a module from scratch. So I started to think about what the minimum amount I needed to add to the API.&lt;br /&gt;&lt;br /&gt;And I thought. And I thought. And I thought. Whenever I have blogged about APIs while working on importlib, it has been in regards to this conundrum of building off of PEP 302's protocols with something that is simple and useful no matter what the storage back-end for modules happened to be.&lt;br /&gt;&lt;br /&gt;Eventually I had an epiphany. Using get_source was not an option because it was missing the path to set __file__ to. Somehow the loader needed to have some concept of paths to set __file__ in some meaningful fashion, even if it wasn't really a file path. If the loader provided some concept of a path, then I could use the loader as if it was using a file-based back-end. If I went with that assumption I could use get_data from PEP 302 in order to get at the source code; get_data(source_path('module')).&lt;br /&gt;&lt;br /&gt;But I hesistated for a long time at using get_data to fetch source code. Having get_source sitting right there was just so tempting! But then I started to consider how to handle reading bytecode. Should I have a get_bytecode method? But I then run into the problem of needing a bytecode_path method to be able to set __file__ probably for modules loaded from bytecode (and when no source is available; new semantics of 3.0). Going that route means I would have added source_path, bytecode_path, and get_bytecode just to read source and bytecode. This still doesn't deal with getting the modification time for source to see if the bytecode is stale or writing bytecode to the storage back-end through the loader.&lt;br /&gt;&lt;br /&gt;Realizing that going the get_bytecode route duplicated functionality needlessly, I went with using get_data to read source and bytecode based on what source_path and bytecode_path return. This keeps the functionality per method simple and mostly unique. It's definitely a "misuse" of get_data as it was not meant to be used this way, but it makes sense and keeps the API simple.&lt;br /&gt;&lt;br /&gt;With all of this put together I can provide an ABC that implements load_module in terms of the PEP 302 protocols and just a couple of other methods that handles all the stuff that is not specific to the back-end being used to store the source or bytecode. For instance, to implement a source loader, one needs to implement:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;get_data&lt;/li&gt;&lt;li&gt;source_path&lt;/li&gt;&lt;li&gt;is_package&lt;/li&gt;&lt;/ul&gt;With those three methods, you get a bunch of other methods for free:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;get_code&lt;/li&gt;&lt;li&gt;get_source (eventually; actually figured this out just before starting this blog post)&lt;/li&gt;&lt;li&gt;load_module&lt;/li&gt;&lt;/ul&gt;As you can see, the methods one needs to implement are rather simple to do for a storage back-end. It does follow a path-like API which isn't really needed for non-file back-ends, e.g. databases, which is unfortunate. But since most people blindly assume __file__ and items in __path__ are paths anyway, I don't think you can get around this without breaking people's code.&lt;br /&gt;&lt;br /&gt;But the big one is when handling source and bytecode together. There you add the above methods plus:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;bytecode_path&lt;/li&gt;&lt;li&gt;source_mtime&lt;/li&gt;&lt;li&gt;write_bytecode&lt;/li&gt;&lt;/ul&gt;Since write_bytecode can be a no-op, you really only need to implement the first two methods to be able to use bytecode. Heck you could implement all three as dud methods and you would end up with a source-only loader that just happened to always try for bytecode. The point is that I have implemented the other methods so that no one else should have to care about what the format for bytecode files are or when to use bytecode or source.&lt;br /&gt;&lt;br /&gt;With all of this done, that leaves just two parts left to implement for the public API (get_source in terms of get_data and source_path along with a decorator I found useful). Once that is done, importlib is semantically done for CPython. I do need to talk to Jython, IronPython, and PyPy to see what they might be missing that I rely on from CPython such that if someone implements a source/bytecode loader it will still work on those VMs even if bytetcode happens to be present (this worry is thanks to &lt;a href="http://www.python.org/dev/peps/pep-0370/"&gt;PEP 370&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-5511937360944836369?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/5511937360944836369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/importlib-is-now-useful-to-other-people.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5511937360944836369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5511937360944836369'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/importlib-is-now-useful-to-other-people.html' title='Importlib is now useful to other people'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-7328060292632940919</id><published>2009-03-08T14:05:00.002-07:00</published><updated>2009-03-08T14:41:31.295-07:00</updated><title type='text'>My first academic research paper is now available online</title><content type='html'>I just got back from &lt;a href="http://www.aosd.net/2009/"&gt;AOSD.09&lt;/a&gt; in Charlottesville, VA. Now that the conference is over my paper that I presented at the conference is &lt;a href="http://doi.acm.org/10.1145/1509239.1509275"&gt;now online at the ACM Portal&lt;/a&gt;. I have also put up a PDF &lt;a href="http://www.cs.ubc.ca/%7Edrifty/papers/cannon09.pdf"&gt;here&lt;/a&gt; for those that are not ACM members.&lt;br /&gt;&lt;br /&gt;You can read the abstract at the ACM page to see what it is about. But just a heads-up that the paper has nothing to do with Python; it's all Java/AspectJ in terms of coding stuff and assumes you know both.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7328060292632940919?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/7328060292632940919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/03/my-first-academic-research-paper-is-now.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7328060292632940919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7328060292632940919'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/03/my-first-academic-research-paper-is-now.html' title='My first academic research paper is now available online'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-7876760425140402395</id><published>2009-02-21T11:11:00.002-08:00</published><updated>2009-02-21T11:12:09.718-08:00</updated><title type='text'>Last day for PyCon early bird registration!</title><content type='html'>&lt;a href="http://us.pycon.org/2009/about/"&gt;PyCon 2009&lt;/a&gt; has its last day for early bird &lt;a href="http://us.pycon.org/2009/registration/"&gt;registration&lt;/a&gt; today (Feb 21)!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7876760425140402395?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/7876760425140402395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/02/last-day-for-pycon-early-bird.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7876760425140402395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7876760425140402395'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/02/last-day-for-pycon-early-bird.html' title='Last day for PyCon early bird registration!'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-8966904530045365492</id><published>2009-02-19T17:29:00.002-08:00</published><updated>2009-02-19T17:40:56.023-08:00</updated><title type='text'>Want some help porting to Py3K? Come to PyCon!</title><content type='html'>Ted Leung made a &lt;a href="http://www.sauria.com/blog/2009/02/18/py3k-sprints/"&gt;good point&lt;/a&gt; that the sprints at PyCon this year are an ideal time to get help with porting your code to Python 3.0. With a good number of core developers showing up this year there will be plenty of experienced people with 3.0 to answer questions in whatever room the core sprint will be in (once I get around to registering the core sprint).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8966904530045365492?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/8966904530045365492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/02/want-some-help-porting-to-py3k-come-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8966904530045365492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8966904530045365492'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/02/want-some-help-porting-to-py3k-come-to.html' title='Want some help porting to Py3K? Come to PyCon!'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-4477440313096857650</id><published>2009-02-19T11:44:00.002-08:00</published><updated>2009-02-19T11:50:59.472-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PyCon'/><title type='text'>Three days left for PyCon early bird registration!</title><content type='html'>Just a reminder that &lt;a href="http://pycon.blogspot.com/2009/02/early-bird-hotel-deadlines-soon.html"&gt;PyCon early bird registration ends in three days&lt;/a&gt;! There are 439 people publicly registered at the moment which, last time I heard, puts us on track to be over 1,000 attendees again! Looks like the economy is not going to suppress attendance at PyCon which is great!&lt;br /&gt;&lt;br /&gt;Actually, this PyCon will probably have the highest number of core developers in attendance than any other previous PyCon thanks to the &lt;a href="http://us.pycon.org/2009/about/summits/language/"&gt;language summit&lt;/a&gt;. That should make the conference interesting to me just from the standpoint of the hallways conversations that will most likely spring up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-4477440313096857650?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/4477440313096857650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/02/three-days-left-for-pycon-early-bird.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/4477440313096857650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/4477440313096857650'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/02/three-days-left-for-pycon-early-bird.html' title='Three days left for PyCon early bird registration!'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-8643467959227751968</id><published>2009-02-10T10:52:00.001-08:00</published><updated>2009-02-10T10:54:46.813-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='version control'/><title type='text'>Benchmark numbers for DVCSs on Python's repository</title><content type='html'>Robert Fendt &lt;a href="https://ldn.linuxfoundation.org/blog-entry/dvcs-follow-what-about-managing-python-repository"&gt;benchmarked Python's repository on various DVCSs&lt;/a&gt;. It confirms my numbers that Bazaar, Mercurial, and Git are all fast enough for our needs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-8643467959227751968?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/8643467959227751968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/02/benchmark-numbers-for-dvcss-on-pythons.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8643467959227751968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/8643467959227751968'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/02/benchmark-numbers-for-dvcss-on-pythons.html' title='Benchmark numbers for DVCSs on Python&apos;s repository'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-5518364507493070081</id><published>2009-02-05T20:45:00.002-08:00</published><updated>2009-02-05T20:51:39.522-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PyCon'/><title type='text'>Invited speakers at PyCon announced</title><content type='html'>When the list of &lt;a href="http://us.pycon.org/2009/conference/talks/"&gt;accepted talks for PyCon 2009&lt;/a&gt; was released, it wasn't the whole story in terms of scheduled content. This year the &lt;a href="http://pycon.blogspot.com/2009/02/invited-speakers-are-announced.html"&gt;program committee decided to do something different&lt;/a&gt; and have &lt;a href="http://us.pycon.org/2009/conference/keynotes/"&gt;invited talks&lt;/a&gt;. Now, short of the keynotes which have not been announced, people have a very clear picture of the great content that is set to be shown at PyCon this year.&lt;br /&gt;&lt;br /&gt;[Full disclosure: I am on the PyCon program committee as well as an invited speaker, although I didn't know I was invited until I got the invitation =) ]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-5518364507493070081?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/5518364507493070081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/02/invited-speakers-at-pycon-announced.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5518364507493070081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5518364507493070081'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/02/invited-speakers-at-pycon-announced.html' title='Invited speakers at PyCon announced'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-2383330022383129345</id><published>2009-02-02T22:01:00.004-08:00</published><updated>2009-02-02T22:09:52.478-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='importlib'/><title type='text'>importlib.import_module() packaged up for PyPI</title><content type='html'>&lt;a href="http://pypi.python.org/pypi?name=importlib"&gt;Importlib is now on the Cheeseshop&lt;/a&gt;. I took what was in the trunk for Python 2.7 and tossed it up. At the moment I know it can go as far back as Python 2.5, but I bet it will go back even farther without issue; just need to get my hands on older interpreters to see how compatible it is.&lt;br /&gt;&lt;br /&gt;With &lt;a href="http://docs.python.org/dev/library/importlib.html"&gt;import_module()&lt;/a&gt; one does not need to call __import__ and try to comprehend how to use it. Instead you use import_module() and get a much saner API.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-2383330022383129345?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/2383330022383129345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/02/importlibimportmodule-packaged-up-for.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/2383330022383129345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/2383330022383129345'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/02/importlibimportmodule-packaged-up-for.html' title='importlib.import_module() packaged up for PyPI'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-5940941554966936858</id><published>2009-01-27T12:27:00.003-08:00</published><updated>2009-01-27T12:32:33.924-08:00</updated><title type='text'>Snakebite announced</title><content type='html'>Well, I am definitely &lt;a href="http://jessenoller.com/2009/01/27/snakebiteorg-the-open-source-dev-network/"&gt;not&lt;/a&gt; &lt;a href="http://ivory.idyll.org/blog/jan-09/snakebite-revealed"&gt;the&lt;/a&gt; &lt;a href="http://holdenweb.blogspot.com/2009/01/snakebiteorg-announced-get-bitten-by.html"&gt;first&lt;/a&gt; person to blog about &lt;a href="http://www.snakebite.org/"&gt;Snakebite&lt;/a&gt;, but it is such a big thing I figured I would do my part to get the word out. Having a huge server farm available to the Python developers to fix platform-specific bugs is going to be great.&lt;br /&gt;&lt;br /&gt;A perk of being the chairman of the infrastructure committee for the PSF is I got to know about this when Trent first started this. But even knowing about it didn't prepare me for the scope of what he has done with Titus' (and others) help.&lt;br /&gt;&lt;br /&gt;And so I big "thank you" from me to Trent for doing this! The man shelled out a lot of time and cash to do this for the benefit for the Python community and I think he deserves all the kudos he has been getting for this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-5940941554966936858?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/5940941554966936858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/01/snakebite-announced.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5940941554966936858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/5940941554966936858'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/01/snakebite-announced.html' title='Snakebite announced'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20144447.post-7986704895358911688</id><published>2009-01-17T16:29:00.004-08:00</published><updated>2009-01-23T15:20:58.948-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='importlib'/><title type='text'>importlib is now in Python 3.1</title><content type='html'>[update: fixed a typo and a broken link]&lt;br /&gt;&lt;br /&gt;Back in the summer of 2006 I interned at Google under Neal Norwitz. Part of what I did that summer was try to figure out how to potentially secure the Python interpreter for embedding into Firefox. I did finally figure out how to secure the interpreter for embedding to protect resources, culminating in a &lt;a href="http://www.cs.ubc.ca/%7Edrifty/papers/python_security.pdf"&gt;paper&lt;/a&gt; for a security course I took at UBC.&lt;br /&gt;&lt;br /&gt;Part of the solution I developed required controlling import such that you couldn't import arbitrary built-in, frozen, and extension modules. As import is currently implemented, that is simply not possible to do in a secure fashion. That meant reworking or rewriting import. Since the import code was known to be a little difficult to work with I decided to rewrite it in pure Python.&lt;br /&gt;&lt;br /&gt;Work began on &lt;a href="http://svn.python.org/view?rev=52154&amp;amp;view=rev"&gt;October 4, 2006&lt;/a&gt;. At the time I was planning on making my Python security work my thesis topic with the long-term goal of making my rewrite of import the official implementation of import. Little did I know how massive of a project this would turn out to be.&lt;br /&gt;&lt;br /&gt;Two years, three months, and 13 days later, &lt;a href="http://svn.python.org/view/python/branches/py3k/Lib/importlib/"&gt;importlib&lt;/a&gt; came into being for Python 3.1 in &lt;a href="http://svn.python.org/view?rev=68698&amp;amp;view=rev"&gt;revision 68698&lt;/a&gt;. Between the beginning and now my security work stopped being my thesis topic (as did anything directly relating to Python), I dropped support for Python 2.x, and I learned part of the reason the C implementation is so difficult to work with is that import's semantics are rather nuanced and require juggling a lot in your head at once. Oh, and allowing different source encodings is evil.&lt;br /&gt;&lt;br /&gt;This is easily the longest amount of time I have ever spent on a single piece of code. One of the surprising things is that the thing is not even 2,000 LOC, including tests! It just took forever to get the semantics fully backwards-compatible (short of some assumptions in the tests, you can currently run the entire test suite for Python with importlib as __import__ and have things work).&lt;br /&gt;&lt;br /&gt;The other thing that held up checking importlib in was being too much of a perfectionist. I think I implemented importlib twice, and I still have plans on how to clean things up. Importlib has become the perfect example that your initial implementation might work, but it most definitely will not be the best implementation you can do. Heck, I still have some things to change to make the code easier to work with and more useful to users.&lt;br /&gt;&lt;br /&gt;The perfectionist part also came out through worrying about the public API. I know people want to have access to all of the code I have written for their own importers. So I have constantly worried about how to expose it in a sane way. But API design is hard, especially when it is in Python's standard library. Get something wrong and you have to live with it for at least one extra release when you add a deprecation. This is why I am going to expose the API slowly over time and probably blog about it so that I can get feedback from people.&lt;br /&gt;&lt;br /&gt;Now that the code is in, what are the long term plans? Well, I have &lt;a href="http://svn.python.org/view/python/branches/py3k/Lib/importlib/NOTES"&gt;notes&lt;/a&gt; with the code that cover what I plan to do. They start with documenting importlib.import_module. That is to be the function that everyone has asked for: a usable interface over __import__. As it stands now the interface is ``import_module(name, package)`` where 'name' is what to import, including relative imports, and 'package' is the package for the calling module. Calling the function returns the specified module, not the top module like __import__; no more fake values in fromlist! I might change the argument names, but I can't think of any other way to make it the API simpler and straight-forward.&lt;br /&gt;&lt;br /&gt;Past that is cleaning up some things through better refactorings, exposing more code, and then exposing more of the code. But the end goal is still to get this all bootstrapped into Python 3.1 so that importlib becomes the actual implementation of __import__.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20144447-7986704895358911688?l=sayspy.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sayspy.blogspot.com/feeds/7986704895358911688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sayspy.blogspot.com/2009/01/importlib-is-now-in-python-31.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7986704895358911688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20144447/posts/default/7986704895358911688'/><link rel='alternate' type='text/html' href='http://sayspy.blogspot.com/2009/01/importlib-is-now-in-python-31.html' title='importlib is now in Python 3.1'/><author><name>Brett</name><uri>http://www.blogger.com/profile/15754007124078149155</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11708585945526518231'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry></feed>