Core Path API
pathlib_next.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.
FsPathLike
Bases: Protocol
Anything implementing __fspath__ -- registered with os.PathLike
so os.fspath() and friends accept it.
Path
Bases: Pathname, Chmod, Stat, BinaryOpen
Base class for manipulating paths with I/O.
__init_subclass__(**kwargs)
Guarantee pathlib_next 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 pathlib_next -- 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-pathlib_next 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.
Source code in src/pathlib_next/path.py
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | |
copy(target, *, overwrite=False, follow_symlinks=True, preserve_metadata=True, recursive=False, ignore_error=None, progress=None)
Copy this file's content to target.
follow_symlinks/preserve_metadata are named to match CPython
3.14's Path.copy() (added after this method); overwrite is our
own extension (3.14 has no equivalent -- it always raises if the
destination exists). preserve_metadata defaults to True here
(unlike 3.14's False) to match this method's pre-existing behavior
of always propagating st_mode; only st_mode is preserved, not
timestamps/xattrs -- full metadata preservation is not implemented.
ignore_error accepts a bool or a callable, matching Path.rm()'s
bool-or-callable contract. True ignores every error; False and
None (the default) fail on the first error. A callable is invoked
as ignore_error(error) -- this call site's own arity -- and, as it
always has here, is a notification hook: the error is suppressed
regardless of what it returns, so handlers like errors.append
(returning None) keep working. Only errors from child copies
during a recursive=True copy are routed here.
progress, when given, is called as progress(path, bytes_copied,
total_size) for every chunk written during each file copy (path
is the source Path being streamed -- self for a single-file
copy, or the relevant child during a recursive=True copy).
bytes_copied increases monotonically per file and reaches
total_size (or None if the size couldn't be determined) at the
end of that file. Directories themselves don't get a progress call
(only the files inside them do). With progress=None (the
default), behavior is unchanged -- no per-chunk overhead. Native
backend transfers that bypass the generic streaming copy (e.g.
SftpPath's asyncssh concurrent fan-out) do not invoke progress;
see docs/divergences.md's "Deliberate extensions" section.
Source code in src/pathlib_next/path.py
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | |
glob(pattern, *, case_sensitive=None, include_hidden=False, recursive=None, dironly=None)
Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.
If pattern contains a "" component, recursion is auto-enabled
(pathlib parity). Pass recursive=False explicitly to disable
recursion even when "" is present, or recursive=True to force
it for a pattern that doesn't contain "**".
Note for remote schemes (http/sftp): a recursive glob walks the
whole remote subtree, one request/roundtrip per directory.
Source code in src/pathlib_next/path.py
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 462 463 464 465 | |
is_hidden()
Return True if the final path component is a hidden file/directory.
Source code in src/pathlib_next/path.py
379 380 381 | |
iterdir()
Yield path objects of the directory contents.
The children are yielded in arbitrary order, and the special entries '.' and '..' are not included.
Source code in src/pathlib_next/path.py
404 405 406 407 408 409 410 411 | |
mkdir(mode=511, parents=False, exist_ok=False)
Create a new directory at this given path.
Source code in src/pathlib_next/path.py
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | |
move(target, *, overwrite=False)
Move this file or directory to target, falling back to copy+unlink/rm if rename is unsupported.
Source code in src/pathlib_next/path.py
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 | |
rename(target)
Rename this file or directory to the given target.
Source code in src/pathlib_next/path.py
685 686 687 688 | |
rglob(pattern, *, case_sensitive=None, include_hidden=False, recursive=True, dironly=None)
Equivalent to glob(f"**/{pattern}", recursive=True).
Source code in src/pathlib_next/path.py
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | |
rm(recursive=False, missing_ok=False, ignore_error=False)
Remove this file or directory, optionally recursively and ignoring errors.
Source code in src/pathlib_next/path.py
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | |
rmdir()
Remove this directory. The directory must be empty.
Source code in src/pathlib_next/path.py
605 606 607 608 609 | |
samefile(other_path)
Return whether other_path is the same or not as this file, by comparing (st_dev, st_ino) when the backend's stat() provides them. Raises NotImplementedError otherwise (e.g. our own FileStat doesn't carry st_dev/st_ino) -- LocalPath gets a real implementation from pathlib.Path via MRO instead of this one.
Source code in src/pathlib_next/path.py
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | |
symlink_to(target, target_is_directory=False, *, force=False)
Make this path a symlink pointing to target.
Signature-compatible with pathlib.Path.symlink_to(); force is a
pathlib_next extension (see docs/divergences.md).
With force=True, an existing entry at this path is removed
first. No filesystem or transport offers an atomic "replace a
symlink" operation, so this is an unlink-then-symlink sequence and
is therefore not atomic: between the two steps the path does not
exist, and a concurrent writer can win the race. It is a
convenience, not a locking primitive.
Only a non-directory entry is removed -- an existing directory at
the link path is left alone and the underlying FileExistsError
(or the backend's equivalent) propagates. Silently deleting a
directory tree is never what force= on a symlink call is asking
for.
Source code in src/pathlib_next/path.py
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | |
touch(mode=438, exist_ok=True)
Create this file with the given access mode, if it doesn't exist.
Raises FileExistsError if exist_ok is False and the file already exists (pathlib parity) instead of silently truncating it.
Source code in src/pathlib_next/path.py
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | |
unlink(missing_ok=False)
Remove this file or link. If the path is a directory, use rmdir() instead.
Source code in src/pathlib_next/path.py
598 599 600 601 602 603 | |
walk(top_down=True, on_error=None, follow_symlinks=False)
Walk the directory tree from this directory, similar to os.walk().
Uses _scandir() rather than iterdir() + a stat() per entry --
for schemes whose listing already carries type metadata (HTTP/DAV
indexes, SFTP listdir_attr, FTP MLSD, S3 list pages), this turns a
remote-tree walk from O(entries) round trips into O(dirs). The
pre-seeded stat is trusted only when follow_symlinks is False
(matching walk()'s own default and the lstat-like semantics of
those listing calls); an explicit follow_symlinks=True always
re-stat()s each entry so a symlink is still resolved.
Source code in src/pathlib_next/path.py
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 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | |
Pathname
Bases: FsPathLike, Generic[_P]
Base class for manipulating paths without I/O.
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
abstractmethod
property
The logical parent of the path.
parents
property
An immutable sequence providing access to the logical ancestors of the path.
parts
abstractmethod
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
abstractmethod
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']
as_posix()
Return the string representation of the path with forward slashes.
Source code in src/pathlib_next/path.py
258 259 260 | |
as_uri()
abstractmethod
Return the path as a URI string.
Source code in src/pathlib_next/path.py
86 87 88 89 | |
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).
Source code in src/pathlib_next/path.py
248 249 250 251 252 253 254 255 256 | |
has_glob_pattern()
Return True if any of the path segments contain glob wildcards.
Source code in src/pathlib_next/path.py
262 263 264 265 266 267 | |
is_absolute()
True if the path is absolute
Source code in src/pathlib_next/path.py
231 232 233 234 | |
is_relative_to(other)
Return True if the path is relative to another path or False.
Source code in src/pathlib_next/path.py
187 188 189 190 191 | |
joinpath(*args)
Combine this path with one or more paths/segments.
Source code in src/pathlib_next/path.py
199 200 201 | |
match(path_pattern, *, case_sensitive=None)
Return True if this path matches the given pattern.
Source code in src/pathlib_next/path.py
236 237 238 239 240 241 242 243 244 245 246 | |
relative_to(other)
abstractmethod
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/pathlib_next/path.py
179 180 181 182 183 184 185 | |
with_name(name)
Return a new path with the name changed.
Source code in src/pathlib_next/path.py
151 152 153 154 155 | |
with_segments(*segments)
abstractmethod
Construct a same-type path instance from new segments.
Source code in src/pathlib_next/path.py
146 147 148 149 | |
with_stem(stem)
Return a new path with the stem changed.
Source code in src/pathlib_next/path.py
157 158 159 | |
with_suffix(suffix)
Return a new path with the suffix changed or added.
Source code in src/pathlib_next/path.py
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | |
pathlib_next.fspath
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).
glob(pattern, *, case_sensitive=None, include_hidden=False, recursive=None, dironly=None)
Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.
A "**" pattern component auto-enables recursion (pathlib parity);
see Path.glob()'s docstring for the recursive= override rules.
Source code in src/pathlib_next/fspath.py
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
PosixPathname
Bases: PurePosixPath, _BaseFSPathname
Pure (no I/O) POSIX-flavour path, implementing the Pathname
protocol on top of pathlib.PurePosixPath.
WindowsPathname
Bases: PureWindowsPath, _BaseFSPathname
Pure (no I/O) Windows-flavour path, implementing the Pathname
protocol on top of pathlib.PureWindowsPath.