summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_pathlib/test_pathlib_abc.py
Commit message (Collapse)AuthorAgeFilesLines
* GH-127807: pathlib ABCs: remove `PathBase._unsupported_msg()` (#127855)Barney Gale2024-12-121-9/+3
| | | | | This method helped us customise the `UnsupportedOperation` message depending on the type. But we're aiming to make `PathBase` a proper ABC soon, so `NotImplementedError` is the right exception to raise there.
* GH-127381: pathlib ABCs: remove remaining uncommon `PathBase` methods (#127714)Barney Gale2024-12-121-12/+0
| | | | | | | | | | | | | | | | | | Remove the following methods from `pathlib._abc.PathBase`: - `expanduser()` - `hardlink_to()` - `touch()` - `chmod()` - `lchmod()` - `owner()` - `group()` - `from_uri()` - `as_uri()` These operations aren't regularly supported in virtual filesystems, so they don't win a place in the `PathBase` interface. (Some of them probably don't deserve a place in `Path` :P.) They're quasi-abstract (except `lchmod()`), and they're not called by other `PathBase` methods.
* GH-127381: pathlib ABCs: remove `PathBase.samefile()` and rarer `is_*()` ↵Barney Gale2024-12-111-81/+0
| | | | | | | | | | (#127709) Remove `PathBase.samefile()`, which is fairly specific to the local FS, and relies on `stat()`, which we're aiming to remove from `PathBase`. Also remove `PathBase.is_mount()`, `is_junction()`, `is_block_device()`, `is_char_device()`, `is_fifo()` and `is_socket()`. These rely on POSIX file type numbers that we're aiming to remove from the `PathBase` API.
* GH-127456: pathlib ABCs: add protocol for path parser (#127494)Barney Gale2024-12-091-53/+8
| | | | | | | | | | Change the default value of `PurePathBase.parser` from `ParserBase()` to `posixpath`. As a result, user subclasses of `PurePathBase` and `PathBase` use POSIX path syntax by default, which is very often desirable. Move `pathlib._abc.ParserBase` to `pathlib._types.Parser`, and convert it to a runtime-checkable protocol. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
* GH-127381: pathlib ABCs: remove `PathBase.unlink()` and `rmdir()` (#127736)Barney Gale2024-12-081-45/+11
| | | | | | | Virtual filesystems don't always make a distinction between deleting files and empty directories, and sometimes support deleting non-empty directories in a single operation. Here we remove `PathBase.unlink()` and `rmdir()`, leaving `_delete()` as the sole deletion method, now made abstract. I hope to drop the underscore prefix later on.
* GH-127381: pathlib ABCs: remove `PathBase.resolve()` and `absolute()` (#127707)Barney Gale2024-12-061-666/+14
| | | | | | | | | Remove our implementation of POSIX path resolution in `PathBase.resolve()`. This functionality is rather fragile and isn't necessary in most cases. It depends on `PathBase.stat()`, which we're looking to remove. Also remove `PathBase.absolute()`. Many legitimate virtual filesystems lack the notion of a 'current directory', so it's wrong to include in the basic interface.
* GH-127381: pathlib ABCs: remove `PathBase.rename()` and `replace()` (#127658)Barney Gale2024-12-061-2/+0
| | | | These methods are obviated by `PathBase.move()`, which can move directories and supports any `PathBase` object as a target.
* GH-125413: Revert addition of `pathlib.Path.scandir()` method (#127377)Barney Gale2024-12-051-39/+9
| | | | | | | | | | Remove documentation for `pathlib.Path.scandir()`, and rename the method to `_scandir()`. In the private pathlib ABCs, make `iterdir()` abstract and call it from `_scandir()`. It's not worthwhile to add this method at the moment - see discussion: https://discuss.python.org/t/ergonomics-of-new-pathlib-path-scandir/71721 Co-authored-by: Steve Dower <steve.dower@microsoft.com>
* gh-127146: Emscripten: Skip segfaults in test suite (#127151)Hood Chatham2024-12-051-1/+3
| | | | Added skips for tests known to cause problems when running on Emscripten. These mostly relate to the limited stack depth on Emscripten.
* GH-127381: pathlib ABCs: remove `PathBase.cwd()` and `home()` (#127427)Barney Gale2024-11-301-2/+0
| | | | | These classmethods presume that the user has retained the original `__init__()` signature, which may not be the case. Also, many virtual filesystems don't provide current or home directories.
* GH-127381: pathlib ABCs: remove `PathBase.lstat()` (#127382)Barney Gale2024-11-291-14/+4
| | | | | | Remove the `PathBase.lstat()` method, which is a trivial variation of `stat()`. No user-facing changes because the pathlib ABCs are still private.
* pathlib tests: move `walk()` tests into their own classes (GH-126651)Barney Gale2024-11-241-6/+19
| | | Move tests for Path.walk() into a new PathWalkTest class, and apply a similar change in tests for the ABCs. This allows us to properly tear down the walk test hierarchy in tearDown(), rather than leaving it to os_helper.rmtree().
* pathlib ABCs: tighten up `resolve()` and `absolute()` (#126611)Barney Gale2024-11-091-23/+17
| | | | | | | | | | | | In `PathBase.resolve()`, raise `UnsupportedOperation` if a non-POSIX path parser is used (our implementation uses `posixpath._realpath()`, which produces incorrect results for non-POSIX path flavours.) Also tweak code to call `self.absolute()` upfront rather than supplying an emulated `getcwd()` function. Adjust `PathBase.absolute()` to work somewhat like `resolve()`. If a POSIX path parser is used, we treat the root directory as the current directory. This is the simplest useful behaviour for concrete path types without a current directory cursor.
* pathlib ABCs: support initializing paths with no arguments (#126608)Barney Gale2024-11-091-0/+1
| | | | | | | | In the past I've equivocated about whether to require at least one argument in the `PurePathBase` (and `PathBase`) initializer, and what the default should be if we make it optional. I now have a local use case that has persuaded me to make it optional and default to the empty string (a `zipp.Path`-like class that treats relative and absolute paths similarly.) Happily this brings the base class more in line with `PurePath` and `Path`.
* pathlib ABCs: defer path joining (#126409)Barney Gale2024-11-051-5/+0
| | | | | | | | Defer joining of path segments in the private `PurePathBase` ABC. The new behaviour matches how the public `PurePath` class handles path segments. This removes a hard-to-grok difference between the ABCs and the main classes. It also slightly reduces the size of `PurePath` objects by eliminating a `_raw_path` slot.
* GH-125413: pathlib ABCs: use `scandir()` to speed up `walk()` (#126262)Barney Gale2024-11-011-2/+2
| | | | | | | Use the new `PathBase.scandir()` method in `PathBase.walk()`, which greatly reduces the number of `PathBase.stat()` calls needed when walking. There are no user-facing changes, because the pathlib ABCs are still private and `Path.walk()` doesn't use the implementation in its superclass.
* GH-125413: pathlib ABCs: use `scandir()` to speed up `glob()` (#126261)Barney Gale2024-11-011-3/+5
| | | | | | | Use the new `PathBase.scandir()` method in `PathBase.glob()`, which greatly reduces the number of `PathBase.stat()` calls needed when globbing. There are no user-facing changes, because the pathlib ABCs are still private and `Path.glob()` doesn't use the implementation in its superclass.
* GH-125413: Add `pathlib.Path.scandir()` method (#126060)Barney Gale2024-11-011-10/+57
| | | | | Add `pathlib.Path.scandir()` as a trivial wrapper of `os.scandir()`. This will be used to implement several `PathBase` methods more efficiently, including methods that provide `Path.copy()`.
* GH-73991: Prune `pathlib.Path.copy()` and `copy_into()` arguments (#123337)Barney Gale2024-08-261-63/+0
| | | | | | | | | | | | | | | | Remove *ignore* and *on_error* arguments from `pathlib.Path.copy[_into]()`, because these arguments are under-designed. Specifically: - *ignore* is appropriated from `shutil.copytree()`, but it's not clear how it should apply when the user copies a non-directory. We've changed the callback signature from the `shutil` version, but I'm not confident the new signature is as good as it can be. - *on_error* is a generalisation of `shutil.copytree()`'s error handling, which is to accumulate exceptions and raise a single `shutil.Error` at the end. It's not obvious which solution is better. Additionally, this arguments may be challenging to implement in future user subclasses of `PathBase`, which might utilise a native recursive copying method.
* GH-73991: Make `pathlib.Path.delete()` private. (#123315)Barney Gale2024-08-261-15/+7
| | | | | | | | Per feedback from Paul Moore on GH-123158, it's better to defer making `Path.delete()` public than ship it with under-designed error handling capabilities. We leave a remnant `_delete()` method, which is used by `move()`. Any functionality not needed by `move()` is deleted.
* GH-73991: Add `pathlib.Path.copy_into()` and `move_into()` (#123314)Barney Gale2024-08-261-0/+30
| | | | | | | | | | | | These two methods accept an *existing* directory path, onto which we join the source path's base name to form the final target path. A possible alternative implementation is to check for directories in `copy()` and `move()` and adjust the target path, which is done in several `shutil` functions. This behaviour is helpful in a shell context, but less so in a stored program that explicitly specifies destinations. For example, a user that calls `Path('foo.py').copy('bar.py')` might not imagine that `bar.py/foo.py` would be created, but under the alternative implementation this will happen if `bar.py` is an existing directory.
* GH-73991: Add `pathlib.Path.move()` (#122073)Barney Gale2024-08-251-0/+119
| | | | | Add a `Path.move()` method that moves a file or directory tree, and returns a new `Path` instance pointing to the target. This method is similar to `shutil.move()`, except that it doesn't accept a *copy_function* argument, and it doesn't check whether the destination is an existing directory.
* GH-73991: Disallow copying directory into itself via `pathlib.Path.copy()` ↵Barney Gale2024-08-231-8/+103
| | | | (#122924)
* GH-120754: Disable buffering in Path.read_bytes (#122111)Cody Maloney2024-08-161-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `Path.read_bytes()` is used to read a whole file. buffering / BufferedIO is focused around making small, possibly interleaved, read/write efficient which doesn't add value in this case. On my Mac, running the benchmark: ```python import pyperf from pathlib import Path def read_all(all_paths): for p in all_paths: p.read_bytes() def read_file(path_obj): path_obj.read_bytes() all_rst = list(Path("Doc").glob("**/*.rst")) all_py = list(Path(".").glob("**/*.py")) assert all_rst, "Should have found rst files" assert all_py, "Should have found python source files" runner = pyperf.Runner() runner.bench_func("read_file_small", read_file, Path("Doc/howto/clinic.rst")) runner.bench_func("read_file_large", read_file, Path("Doc/c-api/typeobj.rst")) ``` before: ```python ..................... read_file_small: Mean +- std dev: 6.80 us +- 0.07 us ..................... read_file_large: Mean +- std dev: 10.8 us +- 0.2 us ```` after: ```python ..................... read_file_small: Mean +- std dev: 5.67 us +- 0.05 us ..................... read_file_large: Mean +- std dev: 9.77 us +- 0.52 us ```
* GH-73991: Rework `pathlib.Path.copytree()` into `copy()` (#122369)Barney Gale2024-08-111-49/+50
| | | | | | | | | | Rename `pathlib.Path.copy()` to `_copy_file()` (i.e. make it private.) Rename `pathlib.Path.copytree()` to `copy()`, and add support for copying non-directories. This simplifies the interface for users, and nicely complements the upcoming `move()` and `delete()` methods (which will also accept any type of file.) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
* GH-73991: Rework `pathlib.Path.rmtree()` into `delete()` (#122368)Barney Gale2024-08-071-59/+32
| | | | | | Rename `pathlib.Path.rmtree()` to `delete()`, and add support for deleting non-directories. This simplifies the interface for users, and nicely complements the upcoming `move()` and `copy()` methods (which will also accept any type of file.)
* GH-73991: Add `pathlib.Path.rmtree()` (#119060)Barney Gale2024-07-201-0/+99
| | | | | | | | | | | Add a `Path.rmtree()` method that removes an entire directory tree, like `shutil.rmtree()`. The signature of the optional *on_error* argument matches the `Path.walk()` argument of the same name, but differs from the *onexc* and *onerror* arguments to `shutil.rmtree()`. Consistency within pathlib is probably more important. In the private pathlib ABCs, we add an implementation based on `walk()`. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
* GH-73991: Support copying directory symlinks on older Windows (#120807)Barney Gale2024-07-031-1/+2
| | | | | Check for `ERROR_INVALID_PARAMETER` when calling `_winapi.CopyFile2()` and raise `UnsupportedOperation`. In `Path.copy()`, handle this exception and fall back to the `PathBase.copy()` implementation.
* GH-73991: Add `pathlib.Path.copytree()` (#120718)Barney Gale2024-06-231-0/+157
| | | | | | | | | | | | | | | | | | | | Add `pathlib.Path.copytree()` method, which recursively copies one directory to another. This differs from `shutil.copytree()` in the following respects: 1. Our method has a *follow_symlinks* argument, whereas shutil's has a *symlinks* argument with an inverted meaning. 2. Our method lacks something like a *copy_function* argument. It always uses `Path.copy()` to copy files. 3. Our method lacks something like a *ignore_dangling_symlinks* argument. Instead, users can filter out danging symlinks with *ignore*, or ignore exceptions with *on_error* 4. Our *ignore* argument is a callable that accepts a single path object, whereas shutil's accepts a path and a list of child filenames. 5. We add an *on_error* argument, which is a callable that accepts an `OSError` instance. (`Path.walk()` also accepts such a callable). Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
* GH-73991: Add follow_symlinks argument to `pathlib.Path.copy()` (#120519)Barney Gale2024-06-191-1/+34
| | | | | | | Add support for not following symlinks in `pathlib.Path.copy()`. On Windows we add the `COPY_FILE_COPY_SYMLINK` flag is following symlinks is disabled. If the source is symlink to a directory, this call will fail with `ERROR_ACCESS_DENIED`. In this case we add `COPY_FILE_DIRECTORY` to the flags and retry. This can fail on old Windowses, which we note in the docs. No news as `copy()` was only just added.
* GH-73991: pathlib ABC tests: add `DummyPath.unlink()` and `rmdir()` (#120715)Barney Gale2024-06-181-1/+51
| | | | | In preparation for the addition of `PathBase.rmtree()`, implement `DummyPath.unlink()` and `rmdir()`, and move corresponding tests into `test_pathlib_abc` so they're run against `DummyPath`.
* GH-73991: Add `pathlib.Path.copy()` (#119058)Barney Gale2024-06-141-0/+62
| | | | | | | | | | | | | | | Add a `Path.copy()` method that copies the content of one file to another. This method is similar to `shutil.copyfile()` but differs in the following ways: - Uses `fcntl.FICLONE` where available (see GH-81338) - Uses `os.copy_file_range` where available (see GH-81340) - Uses `_winapi.CopyFile2` where available, even though this copies more metadata than the other implementations. This makes `WindowsPath.copy()` more similar to `shutil.copy2()`. The method is presently _less_ specified than the `shutil` functions to allow OS-specific optimizations that might copy more or less metadata. Incorporates code from GH-81338 and GH-93152. Co-authored-by: Eryk Sun <eryksun@gmail.com>
* GH-82805: Fix handling of single-dot file extensions in pathlib (#118952)Barney Gale2024-05-251-17/+33
| | | | | | | | | | | | | | | pathlib now treats "`.`" as a valid file extension (suffix). This brings it in line with `os.path.splitext()`. In the (private) pathlib ABCs, we add a new `ParserBase.splitext()` method that splits a path into a `(root, ext)` pair, like `os.path.splitext()`. This method is called by `PurePathBase.stem`, `suffix`, etc. In a future version of pathlib, we might make these base classes public, and so users will be able to define their own `splitext()` method to control file extension splitting. In `pathlib.PurePath` we add optimised `stem`, `suffix` and `suffixes` properties that don't use `splitext()`, which avoids computing the path base name twice.
* GH-119113: Raise `TypeError` from `pathlib.PurePath.with_suffix(None)` (#119124)Barney Gale2024-05-191-1/+3
| | | Restore behaviour from 3.12 when `path.with_suffix(None)` is called.
* GH-115060: Speed up `pathlib.Path.glob()` by omitting initial `stat()` (#117831)Barney Gale2024-04-131-0/+3
| | | | | | | | Since 6258844c, paths that might not exist can be fed into pathlib's globbing implementation, which will call `os.scandir()` / `os.lstat()` only when strictly necessary. This allows us to drop an initial `self.is_dir()` call, which saves a `stat()`. Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
* GH-115060: Speed up `pathlib.Path.glob()` by not scanning literal parts ↵Barney Gale2024-04-121-9/+12
| | | | | | | | | (#117732) Don't bother calling `os.scandir()` to scan for literal pattern segments, like `foo` in `foo/*.py`. Instead, append the segment(s) as-is and call through to the next selector with `exists=False`, which signals that the path might not exist. Subsequent selectors will call `os.scandir()` or `os.lstat()` to filter out missing paths as needed.
* GH-77609: Add recurse_symlinks argument to `pathlib.Path.glob()` (#117311)Barney Gale2024-04-051-62/+7
| | | | | | | | | | | | | | | Replace tri-state `follow_symlinks` with boolean `recurse_symlinks` argument. The new argument controls whether symlinks are followed when expanding recursive `**` wildcards. The possible argument values correspond as follows: follow_symlinks recurse_symlinks =============== ================ False N/A None False True True We therefore drop support for not following symlinks when expanding non-recursive pattern parts; it wasn't requested in the original issue, and it's a feature not found in any shells. This makes the API a easier to grok by eliminating `None` as an option. No news blurb as `follow_symlinks` was new in 3.13.
* GH-114575: Rename `PurePath.pathmod` to `PurePath.parser` (#116513)Barney Gale2024-03-311-38/+38
| | | And rename the private base class from `PathModuleBase` to `ParserBase`.
* GH-116377: Stop raising `ValueError` from `glob.translate()`. (#116378)Barney Gale2024-03-171-2/+0
| | | | | Stop raising `ValueError` from `glob.translate()` when a `**` sub-string appears in a non-recursive pattern segment. This matches `glob.glob()` behaviour.
* pathlib ABCs: follow all symlinks in `PathBase.glob()` (#116293)Barney Gale2024-03-041-37/+32
| | | | | | | Switch the default value of *follow_symlinks* from `None` to `True` in `pathlib._abc.PathBase.glob()` and `rglob()`. This speeds up recursive globbing. No change to the public pathlib classes.
* GH-114610: Fix `pathlib.PurePath.with_stem('')` handling of file extensions ↵Barney Gale2024-02-241-0/+2
| | | | | | | (#114612) Raise `ValueError` if `with_stem('')` is called on a path with a file extension. Paths may only have an empty stem if they also have an empty suffix.
* GH-106747: Make pathlib ABC globbing more consistent with `glob.glob()` ↵Barney Gale2024-02-061-17/+17
| | | | | | | | | | | | (#115056) When expanding `**` wildcards, ensure we add a trailing slash to the topmost directory path. This matches `glob.glob()` behaviour: >>> glob.glob('dirA/**', recursive=True) ['dirA/', 'dirA/dirB', 'dirA/dirB/dirC'] This does not affect `pathlib.Path.glob()`, because trailing slashes aren't supported in pathlib proper.
* pathlib ABCs: drop partial, broken, untested support for `bytes` paths. ↵Barney Gale2024-01-311-0/+25
| | | | | | | (#114777) Methods like `full_match()`, `glob()`, etc, are difficult to make work with byte paths, and it's not worth the effort. This patch makes `PurePathBase` raise `TypeError` when given non-`str` path segments.
* GH-70303: Make `pathlib.Path.glob('**')` return both files and directories ↵Barney Gale2024-01-301-0/+21
| | | | | | | | | | | | (#114684) Return files and directories from `pathlib.Path.glob()` if the pattern ends with `**`. This is more compatible with `PurePath.full_match()` and with other glob implementations such as bash and `glob.glob()`. Users can add a trailing slash to match only directories. In my previous patch I added a `FutureWarning` with the intention of fixing this in Python 3.15. Upon further reflection I think this was an unnecessarily cautious remedy to a clear bug.
* GH-114610: Fix `pathlib._abc.PurePathBase.with_suffix('.ext')` handling of ↵Barney Gale2024-01-301-3/+2
| | | | | | | | | stems (#114613) Raise `ValueError` if `with_suffix('.ext')` is called on a path without a stem. Paths may only have a non-empty suffix if they also have a non-empty stem. ABC-only bugfix; no effect on public classes.
* GH-79634: Speed up pathlib globbing by removing `joinpath()` call. (#114623)Barney Gale2024-01-271-4/+3
| | | | | Remove `self.joinpath('')` call that should have been removed in 6313cdde. This makes `PathBase.glob('')` yield itself *without* adding a trailing slash. It's hard to say whether this is more or less correct, but at least everything else is faster, and there's no behaviour change in the public classes where empty glob patterns are disallowed.
* Cover OS-specific behaviour in `PurePathBase` and `PathBase` tests. (#114633)Barney Gale2024-01-271-0/+625
| | | | Wherever possible, move tests for OS-specific behaviour from `PurePathTest` and `PathTest` to `DummyPurePathTest` and `DummyPathTest`.
* pathlib tests: annotate tests needing symlinks with decorator (#114625)Barney Gale2024-01-261-37/+49
| | | | | | | | Add `@needs_symlinks` decorator for tests that require symlink support in the path class. Also add `@needs_windows` and `@needs_posix` decorators for tests that require a specific a specific path flavour. These aren't much used yet, but will be later.
* GH-73435: Add `pathlib.PurePath.full_match()` (#114350)Barney Gale2024-01-261-23/+75
| | | | | | | | | | | | | | | | In 49f90ba we added support for the recursive wildcard `**` in `pathlib.PurePath.match()`. This should allow arbitrary prefix and suffix matching, like `p.match('foo/**')` or `p.match('**/foo')`, but there's a problem: for relative patterns only, `match()` implicitly inserts a `**` token on the left hand side, causing all patterns to match from the right. As a result, it's impossible to match relative patterns from the left: `PurePath('foo/bar').match('bar/**')` is true! This commit reverts the changes to `match()`, and instead adds a new `full_match()` method that: - Allows empty patterns - Supports the recursive wildcard `**` - Matches the *entire* path when given a relative pattern
* GH-79634: Accept path-like objects as pathlib glob patterns. (#114017)Barney Gale2024-01-201-3/+6
| | | | | | | | | Allow `os.PathLike` objects to be passed as patterns to `pathlib.Path.glob()` and `rglob()`. (It's already possible to use them in `PurePath.match()`) While we're in the area: - Allow empty glob patterns in `PathBase` (but not `Path`) - Speed up globbing in `PathBase` by generating paths with trailing slashes only as a final step, rather than for every intermediate directory. - Simplify and speed up handling of rare patterns involving both `**` and `..` segments.