[Python-Dev] Alternative path suggestion

Nick Coghlan ncoghlan at gmail.com
Sat May 6 08:40:50 CEST 2006


[Nick]
>>> Similarly, I would separate out the extension to a distinct
>>> attribute, as it too uses a different separator from the normal path
>>> elements ('.' most places, but '/' on RISC OS, for example)

[Greg]
>> -1. What constitutes "the extension" is not well-defined in
>> all cases. What about filenames with multiple suffixes,
>> such as "spam.tar.gz"? What part of that would you put in
>> the extension attribute?

[Giovanni]
> .gz of course:
> 
> Path = "foo.tar.gz"
> Path.ext = ".gz"
> Path.name.ext = ".tar"
> Path.name.name.ext = ""
> 
> Which is exactly the *same* thing that os.path.splitext() does. And yes, I do
> use splitext quite a lot.

Remember, the idea with portable path information is to *never* store os.sep 
and os.extsep anywhere in the internal data - those should only be added when 
needed to produce strings to pass to OS-specific functions or to display to users.

So I suggest splitting the internal data into 'path elements separated by 
os.sep', 'name elements separated by os.extsep' and 'the base path' (which can 
be any kind of object that supports __str__, including another path object).

This leads to the following:

import pathlib
from pathlib import Path, PosixPath, WindowsPath, HOMEDIR

pth = Path("~/foo/bar/baz.tar.gz"):

assert pth.basepath == HOMEDIR
assert pth.dirparts == ('foo', 'bar')
assert pth.nameparts == ('baz', 'tar', 'gz')

I would also provide an alternate constructor "from_parts" which looked like:

pth = Path.from_parts(HOMEDIR, ('foo', 'bar'), ('baz', 'tar', 'gz'))

Now consider PosixPath and WindowsPath subclasses:

psx = PosixPath(pth)
win = WindowsPath(pth)

(platform specific Path variants would still accept posix-formatted path 
strings & other Path variants as inputs in addition to path strings formatted 
for the current platform)

# Formatting of the prefix is platform dependent
assert pth.prefix == str(pth.basepath)
assert psx.prefix == "/home/nick/"
assert win.prefix == r"C:\Documents and Settings\Nick\"

# Formatting of the directory path is platform dependent
assert pth.dir == os.sep.join(pth.dirparts + ('',))
assert psx.dir == "foo/bar/"
assert win.dir == r"foo\bar\"

# Formatting of the file name is the same on both platforms
assert pth.name == os.extsep.join(pth.nameparts)
assert psx.name == "baz.tar.gz"
assert win.name == "baz.tar.gz"

# The full path name will then also be platform dependent
assert str(pth) == pth.prefix + pth.dir + pth.name
assert str(psx) == "/home/nick/foo/bar/baz.tar.gz"
assert str(win) == r"C:\Documents and Settings\Nick\foo\bar\baz.tar.gz"

The separation of the directory parts and the name parts also allows the
difference between "/foo/bar/" and "foo/bar" to be represented properly:

pth1 = PosixPath("/foo/bar/")
assert pth1.prefix = '/'
assert pth1.dir == "foo/bar/"
assert pth1.name == ""
assert str(pth1) == "/foo/bar/"

pth2 = PosixPath("/foo/bar")
assert pth2.prefix = '/'
assert pth2.dir == "foo/"
assert pth2.name == "bar"
assert str(pth2) == "/foo/bar"


Operations such as pth.walk() would then return path objects where basepath 
was set to the original path object, and only the relative path was included 
in "dirparts".

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-Dev mailing list