PurePath.parts
parts splits a path into its components (the anchor counts as one). parent drops the last component, parents lists every ancestor up to the anchor, and anchor = drive + root tells you whether the path is rooted.
Common call
p.parent, p.parts
Returns
PurePosixPath('/usr/local'), ('/', 'usr', 'local', 'bin')
Replaces
os.path.dirname and path.split("/")
Watch out
parent of '.' is '.', parent of '/' is '/': it never raises
PurePath.parts / .parent / .parents / .anchor / .drive / .root
→ tuple[str, ...] | PurePath | Sequence[PurePath] | str
Demo
Live evaluation
The anchor (here the root "/") is its own first part.
Try:
Inputs
pathstra path
Code
from pathlib import PurePosixPath PurePosixPath('/usr/local/bin').parts
Result
('/', 'usr', 'local', 'bin')
parents stops at the anchor: for an absolute path the last parent is '/', for a relative one it is '.'. A single-part relative path has '.' as its parent, and the root is its own parent — parent never raises, so a loop 'while p != p.parent' always ends. POSIX paths never have a drive; see PureWindowsPath for 'C:' and UNC shares.
Common patterns
Walk up to find a project root
Check the path and each ancestor for a marker file.
from pathlib import Path def find_root(start, marker='pyproject.toml'): for folder in (start, *start.parents): if (folder / marker).exists(): return folder return None
Grandparent folder
parents[1] is two levels up (parents[0] is parent).
from pathlib import Path repo = Path(__file__).resolve().parents[1]
First folder of a relative path
parts[0] is the top-level directory.
from pathlib import PurePosixPath top = PurePosixPath('src/pkg/mod.py').parts[0] # 'src'
Examples
1. Components as a tuple
from pathlib import PurePosixPath
PurePosixPath('/usr/bin/python3').parts
Returns
('/', 'usr', 'bin', 'python3')2. The containing folder
from pathlib import PurePosixPath
PurePosixPath('/usr/bin/python3').parent
Returns
PurePosixPath('/usr/bin')3. Index into parents
from pathlib import PurePosixPath
p = PurePosixPath('/a/b/c/d')
(p.parents[0], p.parents[2])
Returns
(PurePosixPath('/a/b/c'), PurePosixPath('/a'))4. Negative indexes and slices (3.10+)
from pathlib import PurePosixPath
p = PurePosixPath('/a/b/c')
(p.parents[-1], p.parents[:2])
Returns
(PurePosixPath('/'), (PurePosixPath('/a/b'), PurePosixPath('/a')))5. Parent of a bare name
from pathlib import PurePosixPath
PurePosixPath('notes.txt').parent
Returns
PurePosixPath('.')6. Anchor tells rooted from relative
from pathlib import PurePosixPath
(PurePosixPath('/etc').anchor, PurePosixPath('etc').anchor)
Returns
('/', '')7. Windows drive and root
from pathlib import PureWindowsPath
p = PureWindowsPath('D:/games/save.dat')
(p.drive, p.root, p.parts)
Returns
('D:', '\\', ('D:\\', 'games', 'save.dat'))8. Out of range
from pathlib import PurePosixPath
PurePosixPath('a/b').parents[2]
Returns
IndexError: 2Pitfalls
1. Expecting parent to resolve ".."
parent is lexical: it removes the last component, even when that component is '..'.
parent of '..'
from pathlib import PurePosixPath PurePosixPath('../x').parent.parent
PurePosixPath('.')
resolve() first
from pathlib import Path Path('x').mkdir() Path('x/..').resolve() == Path.cwd().resolve()
True
2. Printing parents directly
parents is a lazy sequence object; its repr is not the list of paths. Convert it with list() or tuple().
repr(parents)
from pathlib import PurePosixPath PurePosixPath('/a/b').parents
<PurePosixPath.parents>
list(parents)
from pathlib import PurePosixPath list(PurePosixPath('/a/b').parents)
[PurePosixPath('/a'), PurePosixPath('/')]
3. Splitting str(path) on "/"
String splitting keeps empty pieces and breaks on Windows separators; parts is already split and normalised.
str.split('/')
'/usr//local/'.split('/')
['', 'usr', '', 'local', '']
.parts
from pathlib import PurePosixPath PurePosixPath('/usr//local/').parts
('/', 'usr', 'local')
When to use
Use it
- Folder of a file (parent) and walking upwards (parents)
- Inspecting the top-level folder of a relative path (parts[0])
- Checking whether a path is rooted (anchor)
Reach for something else
- Resolving ".." or symlinks → Path.resolve()
- Relative path between two locations → relative_to()
Notes
CPython impl
Lib/pathlib/_local.py: parts = (drive + root,) + tail when anchored; parents is a _PathParents sequence built from the parsed tail
drive
Always '' for POSIX; 'C:' or '\\server\share' for Windows
root
'/' or '' on POSIX ('//' for exactly two leading slashes); '\' or '' on Windows
Changed in 3.10
parents supports slices and negative indexes
FAQ
Path(p).parent. For two levels up use p.parent.parent or p.parents[1]. Call resolve() first if the path may contain '..' or be relative.