[Python-Dev] Path.ancestor()

Mike Orr sluggoster at gmail.com
Mon May 1 22:54:21 CEST 2006


This is a potentially long discussion so I'm putting it in a separate thread.

When finding one file relative to another, it's difficult to read
multiple ".parent" attributes stacked together.  Worse, if you have
the wrong number, you end up at the wrong directory level, potentially
causing destructive damage.  Doubly worse, the number of ".parent" is
non-intuitive for those used to the near-universal "." and ".."
conventions.

Say I'm in apps/myapp/bin/myprogram.py and want to add apps/myapp/lib
and apps/shared/lib to sys.path  in a portable way.

    app_root = Path(__file__).realpath().abspath().parent.parent
    assert app_root.parent.name == 'apps'
    sys.path.insert(0, app_root.parent / 'shared/lib')
    sys.path.insert(0, app_root / 'lib')

Yikes!  At least it's better than:

    lib = os.path.join(os.path.dirname(os.path.dirname(x)), "lib")

which is completely unreadable.

(Silence to those who say __path__ is obsolete now that setuptools has
a function for finding a file in an egg.  (1) I don't understand that
part of the setuptools docs.  (2) It will be many months before most
Python programmers are ready to switch to it.)

The tricky thing with "." and ".." is they have a different meaning
depending on whether the original path is a file or directory.  With a
directory there's one less ".parent".  I've played a bit with the
argument and come up with this:

       # N is number of ".."; None (default arg) is special case for ".".
        .ancestor()  =>  "."       =>  p.parent  or  d
       .ancestor(0)  =>  ValueError
        .ancestor(1)  =>  ".."      =>  p.parent.parent  or d.parent
        .ancestor(2)  =>  "../.."  =>  p.parent.parent.parent  or 
d.parent.parent

The simplest alternative is making N the number of ".parent".  This
has some merit, and would solve the original problem of too many
".parent" stacking up.  But it means Path wouldn't have any equivalent
to "." and ".." behavior.

Another alternative is to make .ancestor(0) mean ".".  I don't like
this because "." is a special case, and this should be shown in the
syntax.

Another alternative is to move every number down by 1, so .ancestor(0)
is equivalent to "..".  The tidiness of this is outweighed by the
difficulty of remembering that N is not the number of "..".

--
Mike Orr <sluggoster at gmail.com>
(mso at oz.net address is semi-reliable)


More information about the Python-Dev mailing list