Thanks for the comments here, especially Fredrik's bug report. I guess I should use my unit tests. Will fix tonight.
=== What I've learned from path ===
1. path is useful, much more useful than I expected. Now when I use os.path, supposedly to save myself the pain/time/complexity of installing path.py, I often end up switching to path later ( fortunately that's pretty easy, by design). Is Guido really "lukewarm" about this? I have to wonder if he's tried it...
2. Which features I use: Roughly in order, bytes(), files(), .name, lines(), isdir(), isfile(), .parent, .size, + operator, / operator, .mtime, makedir(), walkfiles(), followed by everything else.
walkfiles() makes me smile.
listdir() is not useful. It's superceded by all those other more specific methods, particularly files().
The optional wildcard argument to files(), et al, is really cool. I forget who suggested it, but I'm glad I decided to try it out instead of instantly showering them with scorn (always my first impulse).
On modern Windows systems, paths are Unicode. So on Windows, path subclasses unicode. Maybe someday I'll use this. :)
3. path subclasses str. A path is-a string. I don't really like it. But it's inescapable. The precedent is overwhelming: the entire tradition of Unix, Windows, C, and Python programming. I've come to see the wisdom of it.
There's a practical aspect, too. Why would you write a path class that you can't use with existing functions that take paths as arguments? I like writing win32file.FileCopy(path1, path2, True), not win32file.FileCopy(str(path1), str(path2), True). The latter is offensive because I'm taking an object that is already the "right" type and explicitly converting it to a type that makes less sense in order to pass it in. Plus it breaks Unicode. (Gotcha.)
That said, my approach has a big, unsightly wart. path inherits three decidedly unwanted features from str: join(), split(), and iterability. This sucks, but it sucks worse when subclasses break promises made by their superclasses (something else I learned from path).
4. Using / and + as semantic sugar for .joinpath(): I don't use / much. But if we're to have an operator that does this, I'm convinced + is a very bad choice. (1) It's confusable with string concatenation, especially since variables and function arguments are untyped. (2) It introduces bugs when you port old str-based code to use path objects. Code like x = mydir + "/foo" looks right, but it's broken. (3) I think string concatenation is actually a more common operation than joinpath() for paths. bakfile = myfile + '.bak' and so forth.
5. Personal preferences I suppressed while making path:
I dislike relative paths. They're an error-prone shortcut. Great for ad hoc shell commands, of course.
Ugh, a lot of these method names stink. But I kept them exactly as in the standard library, where applicable. I hope this makes it easier for people to grab path and start using it.
The dothisdothat() naming convention is Python's worst wart. I'd prefer either doThisDoThat() or do_this_do_that(). But standard library style it is. No point being inconsistent.
I usually don't like "big" classes. path is too big for my taste. But people wanted all these features, and I admit I use them too.