lesscode.org


'Languages' Archives

Ruby-colored Blocks in Python  3

Cat.: Python, Ruby
12. July 2005

Ruby-styled blocks in Python have been something to be a bit anxious about. After spending even a little time working with Ruby, it’s really hard to get the idioms that blocks facilitate out of your head. Dealing with certain types of problems with coroutines just feels right:

File.open("bla.txt") do |file|
   file.read()
end

With the equivalent Python being roughly:

file = open('foo.txt')
try:
    file.read()
finally:
    file.close()

Eewww. What attracted me to Python was its ability to make code read very closely to its intent as it would be described by a human. Resource aquisition/release is one of those things that I’d rather not have to read about when I’m trying to extract the essence of what a piece of code is doing.

Of course, you can get close in most cases by using normal callable passing…

def with_open_file(file, block):
    try:
        block(file)
    finally:
        file.close()

def do_stuff(file):
    file.read()

with_open_file(open('bla.txt'), do_stuff)

… but the Ruby block syntax reads better to these eyes and it seems I’m not the only one. A few weeks ago, Guido had this to say about the block style in relation to recent PEP activity:

That was all before I (re-)discovered yield-expressions (in Ruby!), and mostly in response to the most recent version of PEP 288, with its problem of accessing the generator instance. I now strongly feel that g.next(EXPR) and yield-expressions are the way to go.

So I’ve been following the succession of PEPs that have led us to PEP-342, Coroutines via Enhanced Generators, and PEP-343, Anonymous Block Redux and Generator Enahncements, with great interest.

It looks like there’s a decent chance that we’ll be able to stuff like this in Python 2.5:

 @with_template
 def opening(filename, mode="r"):
     file = open(filename, mode)
     try:
         yield file
     finally:
         file.close()

 with opening("/etc/passwd") as file:
     file.read()

This is accomplished not by adding an implicitly passed block construct like Ruby’s &block, but by adding a basic message passing protocol for generators. Generators will have two new methods: send and throw. The important one here is throw, which tells the generator to raise an Exception at its suspension point. All of this is hidden behind the implementation of with_template (sample implementation in PEP-342).

What I’m interested in understanding more fully is how the PEP proposed enhancements to generators will work in iterative cases or whether that’s planned at all. The examples seem targeted toward resource aquisition/release (which is fine, there’s definitely a strong set of use cases in that area). But I’m interested in understanding how cases similar to Ruby’s IO.foreach will be handled:

IO.foreach("testfile") { |line| puts line }

Note that this is different from Python’s…

for line in open('testfile').readlines():
    print line

… for a few reasons. First, resource aquisition/release is handled within IO.foreach where in the preceding Python snippet, it isn’t really handled at all. Second, IO.foreach reads the file iteratively, calling the block each time, where as an approach using Python generators, such as follows…

def lines(filename):
    f = open(filename)
    try:
        line = f.readline()
        while line:
           yield line
           line = f.readline()
    finally:
        f.close()

for line in lines('foo.txt'):
    raise Exception("this doesn't work")

… falls apart because the exception raised in the iterating block is not automatically signaled back to the generator. There’s no guarantee that the finally block will execute when the iterating block exits.

I have a feeling there’s some aspect of this that I’m not fully grasping. Perhaps Phillip (PING) or someone else with a good understanding of the proposed generator enhancements can stop by and comment; inquiring minds want to know…

Announcing Buildutils  2

Cat.: Python
07. July 2005

I’m pleased to announce an initial version of Buildutils, a set of extension commands to Python’s standard Distutils.

The goal of Buildutils is to distill various development procedures into a set of simple commands under the normal Distutils idiom. All commands are invoked and configured using standard Distutils techniques.

The types of commands available are similar to those that you might throw together with make. The advantage over make is that the commands are written in Python and can use project metadata to provide intelligent defaults for most commands. For example, the announce command can be executed as follows, without any additional configuration beyond your normal setup.py:

pbu announce

The announce command uses the metadata available for the project to put together an announcement email and send it to a set of mailing lists. You can tweak the way the command works by overriding defaults in setup.cfg or on the command line.

I’d really love to see community involvement with this project. I think we can be fairly liberal with adding new and experimental commands. For more information, including a User’s Guide, Command Reference, and installation info, see the Buildutils Project Page.

Wanted: eglob.py  5

Cat.: Wanted, Python
01. July 2005

I’d really like to see an enhanced glob module. Nothing too crazy, just support for recursive wildcards and maybe a nice filtering API. Here’s your test case:

>>> import eglob

… or whatever.

A find function should return an iterator over all matching files and directories. Note that it should be possible to do recursive searches as the iterator is moving. yield kicks so much ass right here.

>>> eglob.find('/etc/**')
<generator object at ...>

Being able to filter the initial glob with such operations as exclude and include (needed?) would be nice. Designing this will be fun - try to abuse chaining generators as much as possible. :)

>>> list(eglob.find('/etc/**').exclude('passwd', 'group', 'init.d/*'))
['/etc/hosts', '/etc/httpd', '/etc/httpd/conf/httpd.conf']

I should be able to pass a extended glob (str, unicode) or a compiled regular expression (sre.SRE_Pattern) to any finding or filtering functions:

>>> list(eglob.find(re.compile(r'^/tmp/.*')))
['/tmp/mysql.sock', '/tmp/foo/bling']

I’d like to filter for directories only or files only:

>>> list(eglob.find('/home/*', directories=1))
['/home/hurly', '/home/curly', '/home/moe']
>>> eglob.find('**/.cvsignore', files=1)

This would be hugely useful in about four projects I’m currently working on.

An Emacs kid-mode  3

Cat.: Python
01. July 2005

I’ve been meaning to take a look at using mmm-mode to get support for < ?python?> blocks in kid templates.

After playing around with wordpress for a few hours, I grabbed php-mode and saw just how easy it is to do sub-modes in emacs. Here’s a simple variation on php-mode’s suggested emacs setup that enables python block support in templates (note that you’ll also need python-mode.el):

;; kid-html-mode
(mmm-add-mode-ext-class nil "\\.kid?\\'" 'html-kid)
(mmm-add-classes
 '((html-kid
    :submode python-mode
    :front "< \\?\\(python\\)?"
    :back "\\?>")))
(add-to-list 'auto-mode-alist '("\\.kid?\\'" . html-mode))

Add that to your .emacs file and then load up a kid template.

Not only do you get syntax coloring but all the other great python-mode.

What sucks about this is that I can’t seem to get it to work reliably with James Clark’s excellent nxml-mode, which I prefer when working with kid templates. I’m trying something like this but it seems flaky:

;; kid-nxml-mode
(mmm-add-mode-ext-class nil "\\.kid?\\'" 'nxml-kid)
(mmm-add-classes
 '((nxml-kid
    :submode python-mode
    :front "< \\?\\(python\\)?"
    :back "\\?>")))
(add-to-list 'auto-mode-alist '("\\.kid?\\'" . nxml-mode))

My suspicion is that this has something to do with the way nxml-mode is loaded, which is kind of weird because I believe it sniffs for a DOCTYPE and/or < ?xml?> declaration.