Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Elegent way to get an iterable of all parents in a path

Working with a path-based resource system, the application needs to find the first working resource that manages a given resource based on paths. I need a succinct, pythonic way to generate the following:

Input:

/house/dogs/ralph/bone

Output:

/house/dogs/ralph/bone
/house/dogs/ralph
/house/dogs
/house

Note: It's okay to use os.path or similar built-ins, but these are not filesystem resources. Output can be anything iterable (list, set, generator, etc.).

like image 483
Bobby Avatar asked Oct 24 '25 20:10

Bobby


2 Answers

Use pathlib. PurePaths offer an abstract interface to path-like objects that have no relationship to the file system. In particular, PurePosixPath is the kind that uses forward slashes (/) as separators:

>>> from pathlib import PurePosixPath
>>> p = PurePosixPath('/house/dogs/ralph/bone')
>>> str(p.parent)
/house/dogs/ralph
>>> str(p.parent.parent)
/house/dogs

You can loop this easily:

p = PurePosixPath(...)
while str(p) != p.root:
    # Do stuff to p
    p = p.parent

A fairly pythonic finishing touch would be to make it a generator:

def receding_path(p):
    p = PurePosixPath(p)
    while str(p) != p.root:
        yield str(p)
        p = p.parent

for item in receding_path('/house/dogs/ralph/bone'):
    # do stuff to each item
like image 157
Mad Physicist Avatar answered Oct 26 '25 10:10

Mad Physicist


Something of a combination of the previous two answers:

import pathlib
import os
def resources(path):
  parts = pathlib.Path(path).parts
  for n in range(len(parts), 1, -1):
    yield os.path.join(*parts[:n])
like image 24
Jeffrey Froman Avatar answered Oct 26 '25 09:10

Jeffrey Froman