-7

I have a function that returns the full path of a specific parent that I look for by a constant name. I am currently using os.path and strings for paths so right now this is done with regular-expressions.

What I want is for example for a constant parent = d to be able to get:

/a/b/c/d/e      -->  /a/b/c/d
/a/b/c/d/e/f    -->  /a/b/c/d
/root/a/b/c/d/e -->  /root/a/b/c/d

Note: as the example shows I don't want to rely on any fixed position from both sides.

I have tried 2 ways but both feels a bit clunky:

  1. Use the parts in order to find the correct parents element:

    >>> path = "/a/b/c/d/e/f"
    >>> parts = Path(path).parts
    >>> parent_index = len(parts) - 1 - parts.index('d') - 1
    >>> Path(path).parents[parent_index]
    PosixPath('/a/b/c/d')
    
  2. Use the parts and concatenate the relevant ones:

    >>> path = "/root/a/b/c/d/e"
    >>> parts = Path(path).parts
    >>> Path(*parts[:parts.index('d')+1])
    PosixPath('/root/a/b/c/d')
    

I would say that the second one seems reasonable, but still, my question is: Is there a more direct, pythonic way to achieve this? The repeated indexing and slicing of the parents feels inefficient and quite confusing.


P.S. In case the part is not present in the path it is enough to raise an exception or any indicator (right now I wrap the code with index above with a try/except).

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • `os.path.dirname(mypath)` – Todd Apr 03 '20 at 18:39
  • @Todd `os.path.dirname("/a/b/c/d/e/f")` will give `'/a/b/c/d/e'` but I am looking for `'/a/b/c/d'` as stated in the example above – Tomerikoo Apr 03 '20 at 20:52
  • call os.path.dirname() again =) – Todd Apr 03 '20 at 21:08
  • If your application is trying to get a listing of all the file paths that terminate in 'd', you might be able to use `glob.glob('**/d', recursive=True)` - but don't do this from root because it'll take forever. You'd probably want to constrain that to specific folder trees. – Todd Apr 03 '20 at 21:15
  • @Todd again, as you can see in the examples, the number of parents varies. As to the `glob`, this will bring up many results from the system and I only need the one in the given file's path – Tomerikoo Apr 03 '20 at 23:26
  • `**` tells glob that the nesting structure can vary, btw. – Todd Apr 03 '20 at 23:28

2 Answers2

3

You can use a while loop instead to keep searching backwards for a parent of the given name:

path = Path("/a/b/c/d/e/f")
while path.name != 'd':
    path = path.parent
    assert path.name, 'No parent found with the given name'
print(path)

This outputs:

/a/b/c/d
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    Thanks @blhsing, that does indeed convey the idea of searching backward in a readable way, and might be more efficient then the `parts` approach as there are now extra lists created and no slicing. I just might use that in my code. Thanks! – Tomerikoo Apr 04 '20 at 13:09
0

You can split and join your string and use index of item +1

path='/a/b/c/d/e/f'
lpath=path.split('/')
index=lpath.index('d')+1
'/'.join(lpath[0:index])

output:

'/a/b/c/d'
Willian Vieira
  • 646
  • 3
  • 9
  • 1
    Hi @Willian and thanks for your answer! I didn' state it explicitly in the question, but I would prefer if the code would be portable and not use string methods – Tomerikoo Apr 03 '20 at 20:55