Wandering Thoughts archives

2009-11-07

Solving unexposed types and the limits of duck typing

When I ran into the issue of the re module not exposing its types, I considered several solutions to my underlying problem of distinguishing strings from compiled regular expressions. For various reasons, I wound up picking the solution that was the least annoying to code; I decided whether something was compiled regular expression by checking to see if it had a .match attribute.

This is the traditional Python approach to the problem; don't check types as such, just check to see if the object has the behavior that you're looking for. However, there's a problem with this, which I can summarize by noting that .match() is a plausible method name for a method on a string-like object, too.

Checking duck typing by checking for attribute names only works when you can be reasonably confidant that the attributes you're looking for are relatively unique. Unfortunately, nicely generic method names are likely to be popular, because they are simple and so broadly applicable, which means that you risk inadvertent collisions.

(A casual scan of my workstation's Python packages turns up several packages with classes with 'match()' methods. While I doubt that any of them are string-like, it does show that the method name is reasonably popular.)

You can improve the accuracy of these checks by testing for more than one attribute, but this rapidly gets both annoying and verbose.

(I'm sure that I'm not the first person to notice this potential drawback.)

Sidebar: the solutions that I can think of

Here's all of the other solutions that I can think of offhand:

  • extract the type from the re module by hand:
    CReType = type(re.compile("."))

  • invert the check by testing to see if the argument is a string, using isinstance() and types.StringTypes, and assume that it is a compiled regexp if it isn't.

  • just call re.compile() on everything, because it turns out it's smart enough to notice if you give it a compiled regular expression instead of a string.

I didn't discover the last solution until I wrote this entry. It's now tempting to revise my code to use it instead of the attribute test, especially since it would make the code shorter.

(This behavior is not officially documented, which is a reason to avoid it.)

python/DuckTypingLimits written at 23:40:56; Add Comment

A gotcha with Bash on Ubuntu 8.04

Suppose that you have an Ubuntu 8.04 system where you have opted to make /bin/sh be bash, the way it used to be in 6.06, and you have an account with /bin/sh as the login shell (for example, you created it with plain useradd). So you log in to the account and everything seems normal and bash-y, until you try to do filename completion and get:

$ cd /-sh: <( compgen -d -- '/' ): No such file or directory

(The text in bold is what you typed before you hit <TAB>.)

I'll give you the fix first: use chsh to change your shell to be /bin/bash. Then everything will work right.

This is one of those interestingly misleading error messages, although if you read very carefully Bash is actually sort of telling you what is going on. Let me give you a related example:

$ cat < 'a random name'
sh: a random name: No such file or directory

This error message has the same form as the first one but makes it much more obvious what the shell is complaining about.

For filename completion, what seems to be going on is that when Bash is operating in sh-compatible mode as a login shell, it is bash-like enough to cause the Ubuntu 8.04 default dotfiles to load the bash command line completion shell functions, but those functions use Bash-specific syntax. As a result, Bash in sh-compatible mode interprets the compgen command seen in the error message as one giant redirection and, of course, cannot find such a peculiarly named file.

(I spent a long time being confused by the error message because I didn't read it carefully and thus didn't realize that it was complaining about a failed redirection instead of a failure to find compgen.)

Short summary: this is an Ubuntu 8.04 bug caused by them not expecting /bin/sh to be Bash and to be used as a login shell, although this is a theoretically supported configuration. This doesn't really surprise me; we've had plenty of experience to the effect that Ubuntu goes off the rails when you depart from their one standard configuration.

linux/BashCompletionIssue written at 01:24:39; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.