4

So I have this python code:

print os.path.commonprefix([r'C:\root\dir',r'C:\root\dir1'])

Real Result

C:\root\dir

Desired result

C:\root

Question 1

Based on os.path.commonprefix documentation:
Return the longest path prefix (taken character-by-character)

Is there a similar function that:
Return the longest path prefix (taken dir by dir)

Question 2

if commonprefix is implemented in os.path why isn't it path oriented, meaning return my desired result and not the real one?

Note:

I can implement this easily by myself but if it is already implemented why not using it?

idanshmu
  • 5,061
  • 6
  • 46
  • 92

3 Answers3

5

is there a path oriented function?

no and yes. commonprefix() can work with arbitrary sequences, not just strings.


Split the path into components and call commonprefix() on that e.g.:

>>> import os
>>> from pathlib import PureWindowsPath
>>> a, b = map(PureWindowsPath, [r'C:\root\dir', r'C:\root\dir1'])
>>> PureWindowsPath(*os.path.commonprefix([a.parts, b.parts]))
PureWindowsPath('C:/root')
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 1
    Without the additional library: os.path.commonprefix([dirname.split(os.sep) for dirname in [r'C:\root\dir', r'C:\root\dir']]) – BurningKarl Jan 11 '15 at 10:18
  • 1
    @user3856011: `pathlib` is in stdlib since Python 3.4 (you can install it on older versions including Python 2). `split(os.sep)` fails in many cases e.g., it won't work on my (posix) machine while the code in the answer works. – jfs Jan 11 '15 at 10:18
  • 1
    Okay, your right, but in this case it works and idanshmu is using Python 2 (print statement) – BurningKarl Jan 11 '15 at 10:22
  • @user3856011: your solution **does not** work in this case on my machine as I've already said. – jfs Jan 11 '15 at 11:07
  • I'm sorry i didn't read your answer carefully. If I replace os.sep with "\\" (i use posix as well), it w – BurningKarl Jan 11 '15 at 11:12
  • Very nice! Unfortunately, `os.path.commonprefix` is typed as if this should be impossible :( see https://github.com/python/typeshed/issues/5009 – shaunc Feb 08 '21 at 03:09
1

Using the pathlib only:

def common_path(path1: Path, path2: Path) -> typing.Optional[Path]:
    while path1 is not None:
        if path2.is_relative_to(path1):
            return path1
        path1 = path1.parent if path1 != path1.parent else None
    return None
Sergey Kostrukov
  • 1,143
  • 15
  • 24
1

Since Python 3.5, you can use os.path.commonpath, which does exactly what you want. Unlike commonprefix, it works dir-by-dir.

Brian McCutchon
  • 8,354
  • 3
  • 33
  • 45