Core Path API
pathapi.path
Object-oriented filesystem paths.
This module provides classes to represent abstract paths and concrete paths with operations that have semantics appropriate for different operating systems.
PathLike = _ty.Union[str, Path]
module-attribute
PurePathLike = _ty.Union[str, Pathname]
module-attribute
__all__ = ['FsPathLike', 'Path', 'PathLike', 'Pathname', 'PurePathLike']
module-attribute
FsPathLike
Bases: Protocol
Anything implementing __fspath__, for annotations. A class qualifies
by defining __fspath__ itself, and os.PathLike recognises it the same
way; this protocol is not registered with os.PathLike, so a class that
does not define one is rejected by os.fspath() with TypeError.
__slots__ = ()
class-attribute
instance-attribute
__fspath__()
Source code in src/pathapi/path/_pure.py
85 86 | |
Path
Bases: Pathname, Move, Copy, Identity, Create, Symlink, Remove, Listing, Resolve, Readlink, Hardlink, Owned, Stat, Chmod, Chown, Utime, BinaryOpen
Base class for manipulating paths with I/O.
__slots__ = ()
class-attribute
instance-attribute
__init_subclass__(**kwargs)
Guarantee pathapi operation precedence in every subclass.
Concrete path classes are routinely built by mixing a pathlib
class with this one -- our own LocalPath does it, and the
documented downstream recipe (class X(PosixPathname, Path)) does
it transitively. Python's MRO then resolves a name to whichever
base declares it first, which for those classes can be pathlib
rather than pathapi -- and which one wins changes with the
interpreter version, because stdlib pathlib keeps gaining and
changing methods (see _OPERATION_NAMES).
Rather than making every downstream implementer rediscover this and hand-write forwarding methods, re-assert our implementations here for any subclass that would otherwise inherit a non-pathapi one. A subclass (or an intermediate mixin) that defines the method itself is always left alone -- this only displaces implementations coming from outside this library.
_OPERATION_NAMES lists what is re-asserted, for two opposite
reasons. Newer stdlib overrides ours: 3.14's copy and move expect
the private _copy_from protocol, so such a class either raises
AttributeError on non-local backends or silently succeeds on local
ones with stdlib's metadata semantics (timestamps preserved, where
ours preserves st_mode), so mtime-based syncs converge on 3.14 and
not before; 3.14's copy_into and move_into call copy() and
move() with stdlib's keywords and defaults. Older stdlib lacks our
keywords: exists(follow_symlinks=) (3.12+), read_text and
write_text(newline=) (3.13+), rglob's extensions, and
symlink_to(force=), which no stdlib has. replace is not listed:
LocalPath keeps stdlib's os.replace, which move() uses to swap a
local file atomically.
A class that mixes a concrete stdlib path with Path but not
LocalPath is a local class too, and gets what LocalPath has for
each name it defines (_local_primitives) wherever stdlib or a
generic default would otherwise answer: the generic is_junction()
and is_mount() say False, so rm(recursive=True) would walk into a
junction, and stdlib's stat(), chmod() and _scandir() do not
take pathapi's arguments.
Source code in src/pathapi/path/_path.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | |
__new__(*args, **kwargs)
Source code in src/pathapi/path/_path.py
183 184 185 186 187 188 189 190 191 | |
is_hidden()
Return True if the final path component is a hidden file/directory.
Source code in src/pathapi/path/_path.py
193 194 195 | |
Pathname
Bases: Generic[_P]
Base class for manipulating paths without I/O.
__slots__ = ()
class-attribute
instance-attribute
anchor
property
drive + root.
drive
property
No generic concept of a drive; always "". LocalPath gets a real one from pathlib on Windows.
name
property
The final path component, if any.
parent
property
The logical parent of the path.
parents
property
An immutable sequence providing access to the logical ancestors of the path.
parts
property
The individual components/parts of the path.
root
property
The root of the path, if any (e.g. "/"). See docs/divergences.md
for how this is derived generically vs. LocalPath's real one.
segments
property
The sequence of path component strings.
stem
property
The final path component, minus its last suffix.
suffix
property
The final component's last suffix, if any.
This includes the leading period. For example: '.txt'
suffixes
property
A list of the final component's suffixes, if any.
These include the leading periods. For example: ['.tar', '.gz']
__eq__(other)
Compare by (exact type, segments).
Identity equality would make is_relative_to() (which decides via
==) return False for every subclass and break paths as dict keys
or set members, so a pure subclass that defines none gets this one.
_BaseFSPathname/LocalPath are unaffected: pathlib.PurePath
precedes Pathname in their MRO and keeps its own __eq__, as
does any class that defines one.
Source code in src/pathapi/path/_pure.py
253 254 255 256 257 258 259 260 261 262 263 264 265 | |
__ge__(other)
Source code in src/pathapi/path/_pure.py
292 293 | |
__gt__(other)
Source code in src/pathapi/path/_pure.py
289 290 | |
__hash__()
Source code in src/pathapi/path/_pure.py
267 268 | |
__le__(other)
Source code in src/pathapi/path/_pure.py
286 287 | |
__lt__(other)
Source code in src/pathapi/path/_pure.py
283 284 | |
__rtruediv__(key)
"prefix" / path, as pathlib supports. self is passed as an
object, so per-instance state it carries (a MemPath backend)
survives, and an absolute self restarts the join.
Source code in src/pathapi/path/_pure.py
301 302 303 304 305 306 307 308 309 310 | |
__truediv__(key)
Source code in src/pathapi/path/_pure.py
295 296 297 298 299 | |
as_posix()
Return the string representation of the path with forward slashes.
Source code in src/pathapi/path/_pure.py
442 443 444 | |
as_uri()
Return the path as a URI string.
Source code in src/pathapi/path/_pure.py
140 141 142 143 | |
full_match(pattern, *, case_sensitive=None)
Return True if this path matches the glob-style pattern
against the whole path (3.13 parity). Unlike match(), this isn't a
right-anchored partial match, and "" matches any number of path
segments (including zero). The root is a component of its own: a
rooted path needs a rooted pattern, or a leading "" that reaches
past it (see glob.full_match). Empty and "." components of
the pattern are ignored, as pathlib parses its pattern as a path.
Source code in src/pathapi/path/_pure.py
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | |
has_glob_pattern()
Return True if any of the path segments contain glob wildcards.
The anchor is not one of them: a Windows extended-length path
(\\?\C:\data, and the \\?\UNC\server\share form) carries a
literal ? in its drive, which is a prefix, not a wildcard -- so a
caller asking "is this a pattern or a plain path?" got True for
every such path.
Source code in src/pathapi/path/_pure.py
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | |
is_absolute()
True if the path is absolute: it has a root. A class whose paths can be rooted without being absolute overrides it.
Source code in src/pathapi/path/_pure.py
351 352 353 354 | |
is_relative_to(other)
Return True if the path is relative to another path or False.
Source code in src/pathapi/path/_pure.py
244 245 246 247 248 249 250 251 | |
joinpath(*args)
Combine this path with one or more paths/segments.
Source code in src/pathapi/path/_pure.py
312 313 314 | |
match(path_pattern, *, case_sensitive=None)
Return True if this path matches the given glob-style pattern.
pathlib's semantics on the running interpreter: a relative pattern
matches the last N segments (from the right), an absolute pattern
must match the whole path, and each segment is matched on its own,
so * never crosses a "/". "**" acts like "*" (use full_match()
for recursive matching). An empty pattern raises ValueError.
A compiled re.Pattern cannot be split into segments; it is matched
against the whole path string instead ("/"-joined segments, so a
URI's scheme and host are never part of it).
Source code in src/pathapi/path/_pure.py
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | |
relative_to(other)
Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError.
Source code in src/pathapi/path/_pure.py
236 237 238 239 240 241 242 | |
with_name(name)
Return a new path with the name changed.
Raises ValueError for an empty name, ".", or a name containing "/",
as pathlib does. Without the check a name such as "../../etc/passwd"
or "x/y" was spliced in verbatim, so a caller relying on pathlib's
validation of an untrusted file name got a path outside the
directory. A bare ".." is accepted, also as pathlib does; use
providers.is_safe_child_name() to reject it. with_stem()/
with_suffix() validate their result through here.
Source code in src/pathapi/path/_pure.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | |
with_segments(*segments)
Construct a same-type path instance from new segments.
Source code in src/pathapi/path/_pure.py
186 187 188 189 | |
with_stem(stem)
Return a new path with the stem changed (validated like
with_name()). From 3.13 on an empty stem is refused when the name
has a suffix, as pathlib does: it would leave a name made of the
suffix alone.
Source code in src/pathapi/path/_pure.py
208 209 210 211 212 213 214 215 216 | |
with_suffix(suffix)
Return a new path with the suffix changed or added.
Source code in src/pathapi/path/_pure.py
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | |
pathapi.fspath
__all__ = ['LocalPath', 'PosixPathname', 'WindowsPathname']
module-attribute
LocalPath
Bases: WindowsPath if name == 'nt' else PosixPath, Path, _BaseFSPathname
The real local filesystem path: pathlib.WindowsPath/PosixPath
with this library's Path mixed in via MRO. Behaves exactly like
pathlib.Path for anything not explicitly overridden here (see
docs/divergences.md).
A class mixing a concrete stdlib path with Path but not this class is
given every function defined here (Path.__init_subclass__), so each one
names stdlib's implementation explicitly instead of calling super().
__slots__ = ()
class-attribute
instance-attribute
chmod(mode, *, follow_symlinks=True)
Source code in src/pathapi/fspath.py
326 327 328 329 330 331 332 333 334 335 336 | |
glob(pattern, *, case_sensitive=None, include_hidden=True, recursive=None, dironly=None, recurse_symlinks=False, native=True, on_error=None, bound_loops=False)
Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.
Same semantics as Path.glob(), including pattern=None (expand the
pattern this path carries) and native= (follow the running
interpreter, or one rule on every version); every separator of this
flavour splits the pattern, and a pattern with a drive or root
raises NonRelativePatternError like pathlib.
Raises the audit event pathlib.Path.glob with (self, pattern), as
pathlib does. pattern=None has no pathlib counterpart and raises none.
Source code in src/pathapi/fspath.py
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | |
is_dir(*, follow_symlinks=True)
Source code in src/pathapi/fspath.py
343 344 345 346 347 348 349 | |
is_file(*, follow_symlinks=True)
Source code in src/pathapi/fspath.py
351 352 353 354 355 356 357 | |
is_junction()
Whether this is a Windows junction. os.path.isjunction() on
3.12+, the reparse tag directly before that.
lstat() reports a junction (IO_REPARSE_TAG_MOUNT_POINT) as a plain
directory -- CPython only rewrites the mode to S_IFLNK for real
symlinks -- so a recursive removal must test for it or it would walk
into one and delete the target's files, as shutil.rmtree guards.
Source code in src/pathapi/fspath.py
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | |
is_mount()
Whether this is a mount point -- a bind mount included, which is how POSIX spells what a junction does on Windows.
Source code in src/pathapi/fspath.py
281 282 283 284 285 286 287 | |
rglob(pattern, *, case_sensitive=None, include_hidden=True, recursive=True, dironly=None, recurse_symlinks=False, native=True, on_error=None, bound_loops=False)
Equivalent to glob(f"**/{pattern}", recursive=True), as
Path.rglob(); raises the audit event pathlib.Path.rglob with
(self, pattern), and from 3.13 the pathlib.Path.glob event of the
glob() it stands for, as pathlib does. pattern=None raises none.
Source code in src/pathapi/fspath.py
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | |
stat(*, follow_symlinks=True)
Source code in src/pathapi/fspath.py
318 319 320 321 322 323 324 | |
walk(top_down=True, on_error=None, follow_symlinks=False)
Source code in src/pathapi/fspath.py
289 290 291 292 293 294 295 | |
PosixPathname
Bases: PurePosixPath, _BaseFSPathname
Pure (no I/O) POSIX-flavour path, implementing the Pathname
protocol on top of pathlib.PurePosixPath.
__slots__ = ()
class-attribute
instance-attribute
WindowsPathname
Bases: PureWindowsPath, _BaseFSPathname
Pure (no I/O) Windows-flavour path, implementing the Pathname
protocol on top of pathlib.PureWindowsPath.
__slots__ = ()
class-attribute
instance-attribute
pathapi.FileStat(st_mode=None, st_size=0, st_mtime=0, is_dir=False, size_known=True)
Bases: FileStatLike
Concrete, slotted FileStatLike for backends without a real
os.stat_result (e.g. MemPath, an HTTP index). from_path() builds one
from any object with a stat() method, or passes a FileStat through
unchanged.
Source code in src/pathapi/_filestat.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
__slots__ = _FIELDS + ('mode_known', 'size_known')
class-attribute
instance-attribute
mode_known = bool(st_mode)
instance-attribute
size_known = size_known
instance-attribute
st_atime = 0
instance-attribute
st_ctime = 0
instance-attribute
st_gid = 0
instance-attribute
st_mode = st_mode or (_stat.S_IFDIR | 365 if is_dir else _stat.S_IFREG | 292)
instance-attribute
st_mtime = st_mtime
instance-attribute
st_nlink = 1
instance-attribute
st_size = st_size
instance-attribute
st_uid = 0
instance-attribute
__getitem__(key)
Source code in src/pathapi/_filestat.py
102 103 | |
__repr__()
Source code in src/pathapi/_filestat.py
109 110 111 112 113 114 115 | |
__str__()
Source code in src/pathapi/_filestat.py
117 118 119 | |
from_path(path, *, follow_symlink=True)
classmethod
Source code in src/pathapi/_filestat.py
145 146 147 148 149 150 151 | |
from_stat(stat)
classmethod
Copy any stat-like object's (os.stat_result, paramiko's
SFTPAttributes, ...) recognized fields into a fresh FileStat,
so downstream code (e.g. .is_dir()) can rely on a uniform type.
Passes an already-FileStat through unchanged. The copied mode
counts as backend-reported (mode_known) unless the source says
otherwise or carries no mode at all (missing, None or 0).
A missing or None field becomes 0: paramiko's SFTPAttributes
leaves every field the server did not send as None, which made
is_dir() and repr() raise TypeError.
Source code in src/pathapi/_filestat.py
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
is_block_device()
Whether this path is a block device.
Source code in src/pathapi/_filestat.py
172 173 174 175 176 | |
is_char_device()
Whether this path is a character device.
Source code in src/pathapi/_filestat.py
178 179 180 181 182 | |
is_dir()
Whether this path is a directory.
Source code in src/pathapi/_filestat.py
153 154 155 156 157 | |
is_fifo()
Whether this path is a FIFO.
Source code in src/pathapi/_filestat.py
184 185 186 187 188 | |
is_file()
Whether this path is a regular file (also True for symlinks pointing to regular files).
Source code in src/pathapi/_filestat.py
159 160 161 162 163 164 | |
is_socket()
Whether this path is a socket.
Source code in src/pathapi/_filestat.py
190 191 192 193 194 | |
is_symlink()
Whether this path is a symbolic link.
Source code in src/pathapi/_filestat.py
166 167 168 169 170 | |
items()
Source code in src/pathapi/_filestat.py
105 106 107 | |
setmode(value, isdir=None)
Source code in src/pathapi/_filestat.py
93 94 95 96 97 98 99 100 | |
settime(value)
Source code in src/pathapi/_filestat.py
90 91 | |