| 
									
										
										
										
											2024-01-13 08:47:00 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | Abstract base classes for rich path objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This module is published as a PyPI package called "pathlib-abc". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This module is also a *PRIVATE* part of the Python standard library, where | 
					
						
							|  |  |  | it's developed alongside pathlib. If it finds success and maturity as a PyPI | 
					
						
							|  |  |  | package, it could become a public part of the standard library. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Two base classes are defined here -- PurePathBase and PathBase -- that | 
					
						
							|  |  |  | resemble pathlib's PurePath and Path respectively. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | import functools | 
					
						
							| 
									
										
										
										
											2024-06-07 17:59:34 +01:00
										 |  |  | import operator | 
					
						
							| 
									
										
										
										
											2024-12-09 18:31:22 +00:00
										 |  |  | import posixpath | 
					
						
							| 
									
										
										
										
											2024-12-06 18:10:00 +00:00
										 |  |  | from errno import EINVAL | 
					
						
							| 
									
										
										
										
											2024-06-07 17:59:34 +01:00
										 |  |  | from glob import _GlobberBase, _no_recurse_symlinks | 
					
						
							| 
									
										
										
										
											2024-12-11 00:09:55 +00:00
										 |  |  | from stat import S_ISDIR, S_ISLNK, S_ISREG | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  | from pathlib._os import copyfileobj | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = ["UnsupportedOperation"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UnsupportedOperation(NotImplementedError): | 
					
						
							|  |  |  |     """An exception that is raised when an unsupported operation is attempted.
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     pass | 
					
						
							| 
									
										
										
										
											2024-05-03 21:29:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 23:08:18 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-30 21:18:09 +01:00
										 |  |  | @functools.cache | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  | def _is_case_sensitive(parser): | 
					
						
							|  |  |  |     return parser.normcase('Aa') == 'Aa' | 
					
						
							| 
									
										
										
										
											2023-05-02 22:51:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-25 17:41:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-07 17:59:34 +01:00
										 |  |  | class PathGlobber(_GlobberBase): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Class providing shell-style globbing for path objects. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lexists = operator.methodcaller('exists', follow_symlinks=False) | 
					
						
							|  |  |  |     add_slash = operator.methodcaller('joinpath', '') | 
					
						
							| 
									
										
										
										
											2024-12-05 21:39:43 +00:00
										 |  |  |     scandir = operator.methodcaller('_scandir') | 
					
						
							| 
									
										
										
										
											2024-06-07 17:59:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def concat_path(path, text): | 
					
						
							|  |  |  |         """Appends text to the given path.""" | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         return path.with_segments(str(path) + text) | 
					
						
							| 
									
										
										
										
											2024-06-07 17:59:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 15:07:40 +00:00
										 |  |  | class PurePathBase: | 
					
						
							| 
									
										
										
											
												GH-110109: Add `pathlib._PurePathBase` (#110670)
Add private `pathlib._PurePathBase` class: a private superclass of both `PurePath` and `_PathBase`. Unlike `PurePath`, it does not define any of these special methods: `__fspath__`, `__bytes__`, `__reduce__`, `__hash__`, `__eq__`, `__lt__`, `__le__`, `__gt__`, `__ge__`. Its initializer and path joining methods accept only strings, not os.PathLike objects more broadly.
This is important for supporting *virtual paths*: user subclasses of `_PathBase` that provide access to archive files, FTP servers, etc. In these classes, the above methods should be implemented by users only as appropriate, with due consideration for the hash/equality of any backing objects, such as file objects or sockets.
											
										 
											2023-12-08 17:39:04 +00:00
										 |  |  |     """Base class for pure path objects.
 | 
					
						
							| 
									
										
										
										
											2018-02-19 08:36:32 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												GH-110109: Add `pathlib._PurePathBase` (#110670)
Add private `pathlib._PurePathBase` class: a private superclass of both `PurePath` and `_PathBase`. Unlike `PurePath`, it does not define any of these special methods: `__fspath__`, `__bytes__`, `__reduce__`, `__hash__`, `__eq__`, `__lt__`, `__le__`, `__gt__`, `__ge__`. Its initializer and path joining methods accept only strings, not os.PathLike objects more broadly.
This is important for supporting *virtual paths*: user subclasses of `_PathBase` that provide access to archive files, FTP servers, etc. In these classes, the above methods should be implemented by users only as appropriate, with due consideration for the hash/equality of any backing objects, such as file objects or sockets.
											
										 
											2023-12-08 17:39:04 +00:00
										 |  |  |     This class *does not* provide several magic methods that are defined in | 
					
						
							|  |  |  |     its subclass PurePath. They are: __fspath__, __bytes__, __reduce__, | 
					
						
							|  |  |  |     __hash__, __eq__, __lt__, __le__, __gt__, __ge__. Its initializer and path | 
					
						
							|  |  |  |     joining methods accept only strings, not os.PathLike objects more broadly. | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-04-09 18:40:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     __slots__ = ( | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         # The `_raw_paths` slot stores unjoined string paths. This is set in | 
					
						
							|  |  |  |         # the `__init__()` method. | 
					
						
							|  |  |  |         '_raw_paths', | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-12-09 18:31:22 +00:00
										 |  |  |     parser = posixpath | 
					
						
							| 
									
										
										
										
											2024-06-07 17:59:34 +01:00
										 |  |  |     _globber = PathGlobber | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-09 18:21:53 +00:00
										 |  |  |     def __init__(self, *args): | 
					
						
							|  |  |  |         for arg in args: | 
					
						
							|  |  |  |             if not isinstance(arg, str): | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |                 raise TypeError( | 
					
						
							| 
									
										
										
										
											2024-11-09 18:21:53 +00:00
										 |  |  |                     f"argument should be a str, not {type(arg).__name__!r}") | 
					
						
							|  |  |  |         self._raw_paths = list(args) | 
					
						
							| 
									
										
										
											
												GH-110109: Add `pathlib._PurePathBase` (#110670)
Add private `pathlib._PurePathBase` class: a private superclass of both `PurePath` and `_PathBase`. Unlike `PurePath`, it does not define any of these special methods: `__fspath__`, `__bytes__`, `__reduce__`, `__hash__`, `__eq__`, `__lt__`, `__le__`, `__gt__`, `__ge__`. Its initializer and path joining methods accept only strings, not os.PathLike objects more broadly.
This is important for supporting *virtual paths*: user subclasses of `_PathBase` that provide access to archive files, FTP servers, etc. In these classes, the above methods should be implemented by users only as appropriate, with due consideration for the hash/equality of any backing objects, such as file objects or sockets.
											
										 
											2023-12-08 17:39:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 20:04:53 +01:00
										 |  |  |     def with_segments(self, *pathsegments): | 
					
						
							|  |  |  |         """Construct a new path object from any number of path-like objects.
 | 
					
						
							|  |  |  |         Subclasses may override this method to customize how new path objects | 
					
						
							|  |  |  |         are created from methods like `iterdir()`. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return type(self)(*pathsegments) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     def __str__(self): | 
					
						
							|  |  |  |         """Return the string representation of the path, suitable for
 | 
					
						
							|  |  |  |         passing to system calls."""
 | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         paths = self._raw_paths | 
					
						
							|  |  |  |         if len(paths) == 1: | 
					
						
							|  |  |  |             return paths[0] | 
					
						
							|  |  |  |         elif paths: | 
					
						
							|  |  |  |             # Join path segments from the initializer. | 
					
						
							|  |  |  |             path = self.parser.join(*paths) | 
					
						
							|  |  |  |             # Cache the joined path. | 
					
						
							|  |  |  |             paths.clear() | 
					
						
							|  |  |  |             paths.append(path) | 
					
						
							|  |  |  |             return path | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             paths.append('') | 
					
						
							|  |  |  |             return '' | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def as_posix(self): | 
					
						
							|  |  |  |         """Return the string representation of the path with forward (/)
 | 
					
						
							|  |  |  |         slashes."""
 | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         return str(self).replace(self.parser.sep, '/') | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 19:57:11 +01:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def drive(self): | 
					
						
							|  |  |  |         """The drive prefix (letter or UNC path), if any.""" | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         return self.parser.splitdrive(self.anchor)[0] | 
					
						
							| 
									
										
										
										
											2023-04-03 19:57:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def root(self): | 
					
						
							|  |  |  |         """The root of the path, if any.""" | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         return self.parser.splitdrive(self.anchor)[1] | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def anchor(self): | 
					
						
							|  |  |  |         """The concatenation of the drive and root, or ''.""" | 
					
						
							| 
									
										
										
										
											2024-01-14 23:06:04 +00:00
										 |  |  |         return self._stack[0] | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def name(self): | 
					
						
							|  |  |  |         """The final path component, if any.""" | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         return self.parser.split(str(self))[1] | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def suffix(self): | 
					
						
							| 
									
										
										
										
											2019-11-02 18:46:24 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         The final component's last suffix, if any. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This includes the leading period. For example: '.txt' | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-05-25 21:01:36 +01:00
										 |  |  |         return self.parser.splitext(self.name)[1] | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def suffixes(self): | 
					
						
							| 
									
										
										
										
											2019-11-02 18:46:24 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         A list of the final component's suffixes, if any. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         These include the leading periods. For example: ['.tar', '.gz'] | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-05-25 21:01:36 +01:00
										 |  |  |         split = self.parser.splitext | 
					
						
							|  |  |  |         stem, suffix = split(self.name) | 
					
						
							|  |  |  |         suffixes = [] | 
					
						
							|  |  |  |         while suffix: | 
					
						
							|  |  |  |             suffixes.append(suffix) | 
					
						
							|  |  |  |             stem, suffix = split(stem) | 
					
						
							|  |  |  |         return suffixes[::-1] | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def stem(self): | 
					
						
							|  |  |  |         """The final path component, minus its last suffix.""" | 
					
						
							| 
									
										
										
										
											2024-05-25 21:01:36 +01:00
										 |  |  |         return self.parser.splitext(self.name)[0] | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def with_name(self, name): | 
					
						
							|  |  |  |         """Return a new path with the file name changed.""" | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         split = self.parser.split | 
					
						
							| 
									
										
										
										
											2024-01-14 21:49:53 +00:00
										 |  |  |         if split(name)[0]: | 
					
						
							| 
									
										
										
										
											2023-11-25 17:19:38 +00:00
										 |  |  |             raise ValueError(f"Invalid name {name!r}") | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         return self.with_segments(split(str(self))[0], name) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-19 17:29:49 +02:00
										 |  |  |     def with_stem(self, stem): | 
					
						
							|  |  |  |         """Return a new path with the stem changed.""" | 
					
						
							| 
									
										
										
										
											2024-02-24 19:37:03 +00:00
										 |  |  |         suffix = self.suffix | 
					
						
							|  |  |  |         if not suffix: | 
					
						
							|  |  |  |             return self.with_name(stem) | 
					
						
							|  |  |  |         elif not stem: | 
					
						
							|  |  |  |             # If the suffix is non-empty, we can't make the stem empty. | 
					
						
							|  |  |  |             raise ValueError(f"{self!r} has a non-empty suffix") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return self.with_name(stem + suffix) | 
					
						
							| 
									
										
										
										
											2020-04-19 17:29:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     def with_suffix(self, suffix): | 
					
						
							| 
									
										
										
										
											2018-08-03 22:49:42 +02:00
										 |  |  |         """Return a new path with the file suffix changed.  If the path
 | 
					
						
							|  |  |  |         has no suffix, add given suffix.  If the given suffix is an empty | 
					
						
							|  |  |  |         string, remove the suffix from the path. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-30 14:25:16 +00:00
										 |  |  |         stem = self.stem | 
					
						
							| 
									
										
										
										
											2024-05-19 17:04:56 +01:00
										 |  |  |         if not stem: | 
					
						
							| 
									
										
										
										
											2024-02-24 19:37:03 +00:00
										 |  |  |             # If the stem is empty, we can't make the suffix non-empty. | 
					
						
							| 
									
										
										
										
											2024-01-30 14:25:16 +00:00
										 |  |  |             raise ValueError(f"{self!r} has an empty name") | 
					
						
							| 
									
										
										
										
											2024-05-25 21:01:36 +01:00
										 |  |  |         elif suffix and not suffix.startswith('.'): | 
					
						
							| 
									
										
										
										
											2023-11-25 17:19:38 +00:00
										 |  |  |             raise ValueError(f"Invalid suffix {suffix!r}") | 
					
						
							| 
									
										
										
										
											2024-05-19 17:04:56 +01:00
										 |  |  |         else: | 
					
						
							|  |  |  |             return self.with_name(stem + suffix) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-05 22:56:04 +00:00
										 |  |  |     def relative_to(self, other, *, walk_up=False): | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """Return the relative path to another path identified by the passed
 | 
					
						
							|  |  |  |         arguments.  If the operation is not possible (because this is not | 
					
						
							| 
									
										
										
										
											2022-10-29 01:20:14 +02:00
										 |  |  |         related to the other path), raise ValueError. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The *walk_up* parameter controls whether `..` may be used to resolve | 
					
						
							|  |  |  |         the path. | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-05 22:56:04 +00:00
										 |  |  |         if not isinstance(other, PurePathBase): | 
					
						
							| 
									
										
										
										
											2023-11-12 22:59:17 +00:00
										 |  |  |             other = self.with_segments(other) | 
					
						
							| 
									
										
										
										
											2024-01-09 23:04:14 +00:00
										 |  |  |         anchor0, parts0 = self._stack | 
					
						
							|  |  |  |         anchor1, parts1 = other._stack | 
					
						
							|  |  |  |         if anchor0 != anchor1: | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |             raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") | 
					
						
							| 
									
										
										
										
											2024-01-09 23:04:14 +00:00
										 |  |  |         while parts0 and parts1 and parts0[-1] == parts1[-1]: | 
					
						
							|  |  |  |             parts0.pop() | 
					
						
							|  |  |  |             parts1.pop() | 
					
						
							|  |  |  |         for part in parts1: | 
					
						
							|  |  |  |             if not part or part == '.': | 
					
						
							|  |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2023-07-26 21:44:55 +02:00
										 |  |  |             elif not walk_up: | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |                 raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") | 
					
						
							| 
									
										
										
										
											2024-01-09 23:04:14 +00:00
										 |  |  |             elif part == '..': | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |                 raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") | 
					
						
							| 
									
										
										
										
											2024-01-09 23:04:14 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 parts0.append('..') | 
					
						
							| 
									
										
										
										
											2024-11-09 18:21:53 +00:00
										 |  |  |         return self.with_segments(*reversed(parts0)) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-05 22:56:04 +00:00
										 |  |  |     def is_relative_to(self, other): | 
					
						
							| 
									
										
										
										
											2019-08-13 14:54:02 -05:00
										 |  |  |         """Return True if the path is relative to another path or False.
 | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-05 22:56:04 +00:00
										 |  |  |         if not isinstance(other, PurePathBase): | 
					
						
							| 
									
										
										
										
											2023-11-12 22:59:17 +00:00
										 |  |  |             other = self.with_segments(other) | 
					
						
							| 
									
										
										
										
											2024-01-09 23:04:14 +00:00
										 |  |  |         anchor0, parts0 = self._stack | 
					
						
							|  |  |  |         anchor1, parts1 = other._stack | 
					
						
							|  |  |  |         if anchor0 != anchor1: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         while parts0 and parts1 and parts0[-1] == parts1[-1]: | 
					
						
							|  |  |  |             parts0.pop() | 
					
						
							|  |  |  |             parts1.pop() | 
					
						
							|  |  |  |         for part in parts1: | 
					
						
							|  |  |  |             if part and part != '.': | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2019-08-13 14:54:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def parts(self): | 
					
						
							|  |  |  |         """An object providing sequence-like access to the
 | 
					
						
							|  |  |  |         components in the filesystem path."""
 | 
					
						
							| 
									
										
										
										
											2024-01-09 22:46:50 +00:00
										 |  |  |         anchor, parts = self._stack | 
					
						
							|  |  |  |         if anchor: | 
					
						
							|  |  |  |             parts.append(anchor) | 
					
						
							|  |  |  |         return tuple(reversed(parts)) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 20:04:53 +01:00
										 |  |  |     def joinpath(self, *pathsegments): | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """Combine this path with one or several arguments, and return a
 | 
					
						
							|  |  |  |         new path representing either a subpath (if all arguments are relative | 
					
						
							|  |  |  |         paths) or a totally different path (if one of the arguments is | 
					
						
							|  |  |  |         anchored). | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         return self.with_segments(*self._raw_paths, *pathsegments) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __truediv__(self, key): | 
					
						
							| 
									
										
										
										
											2019-08-08 01:41:10 -04:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |             return self.with_segments(*self._raw_paths, key) | 
					
						
							| 
									
										
										
										
											2019-08-08 01:41:10 -04:00
										 |  |  |         except TypeError: | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __rtruediv__(self, key): | 
					
						
							| 
									
										
										
										
											2019-08-08 01:41:10 -04:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |             return self.with_segments(key, *self._raw_paths) | 
					
						
							| 
									
										
										
										
											2019-08-08 01:41:10 -04:00
										 |  |  |         except TypeError: | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 19:50:23 +00:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def _stack(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Split the path into a 2-tuple (anchor, parts), where *anchor* is the | 
					
						
							|  |  |  |         uppermost parent of the path (equivalent to path.parents[-1]), and | 
					
						
							|  |  |  |         *parts* is a reversed list of parts following the anchor. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         split = self.parser.split | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         path = str(self) | 
					
						
							| 
									
										
										
										
											2024-01-09 19:50:23 +00:00
										 |  |  |         parent, name = split(path) | 
					
						
							|  |  |  |         names = [] | 
					
						
							|  |  |  |         while path != parent: | 
					
						
							|  |  |  |             names.append(name) | 
					
						
							|  |  |  |             path = parent | 
					
						
							|  |  |  |             parent, name = split(path) | 
					
						
							|  |  |  |         return path, names | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def parent(self): | 
					
						
							|  |  |  |         """The logical parent of the path.""" | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         path = str(self) | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         parent = self.parser.split(path)[0] | 
					
						
							| 
									
										
										
										
											2024-01-06 21:17:51 +00:00
										 |  |  |         if path != parent: | 
					
						
							| 
									
										
										
										
											2024-12-06 21:39:45 +00:00
										 |  |  |             return self.with_segments(parent) | 
					
						
							| 
									
										
										
										
											2024-01-06 21:17:51 +00:00
										 |  |  |         return self | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def parents(self): | 
					
						
							|  |  |  |         """A sequence of this path's logical parents.""" | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |         split = self.parser.split | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         path = str(self) | 
					
						
							| 
									
										
										
										
											2024-01-14 21:49:53 +00:00
										 |  |  |         parent = split(path)[0] | 
					
						
							| 
									
										
										
										
											2024-01-06 21:17:51 +00:00
										 |  |  |         parents = [] | 
					
						
							|  |  |  |         while path != parent: | 
					
						
							|  |  |  |             parents.append(self.with_segments(parent)) | 
					
						
							|  |  |  |             path = parent | 
					
						
							| 
									
										
										
										
											2024-01-14 21:49:53 +00:00
										 |  |  |             parent = split(path)[0] | 
					
						
							| 
									
										
										
										
											2024-01-06 21:17:51 +00:00
										 |  |  |         return tuple(parents) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_absolute(self): | 
					
						
							|  |  |  |         """True if the path is absolute (has both a root and, if applicable,
 | 
					
						
							|  |  |  |         a drive)."""
 | 
					
						
							| 
									
										
										
										
											2024-11-05 21:19:36 +00:00
										 |  |  |         return self.parser.isabs(str(self)) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def _pattern_str(self): | 
					
						
							|  |  |  |         """The path expressed as a string, for use in pattern-matching.""" | 
					
						
							|  |  |  |         return str(self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 23:29:31 +05:30
										 |  |  |     def match(self, path_pattern, *, case_sensitive=None): | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |         Return True if this path matches the given pattern. If the pattern is | 
					
						
							|  |  |  |         relative, matching is done from the right; otherwise, the entire path | 
					
						
							|  |  |  |         is matched. The recursive wildcard '**' is *not* supported by this | 
					
						
							|  |  |  |         method. | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-12-09 15:07:40 +00:00
										 |  |  |         if not isinstance(path_pattern, PurePathBase): | 
					
						
							| 
									
										
										
										
											2023-05-30 21:18:09 +01:00
										 |  |  |             path_pattern = self.with_segments(path_pattern) | 
					
						
							| 
									
										
										
										
											2023-05-18 23:29:31 +05:30
										 |  |  |         if case_sensitive is None: | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |             case_sensitive = _is_case_sensitive(self.parser) | 
					
						
							|  |  |  |         sep = path_pattern.parser.sep | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |         path_parts = self.parts[::-1] | 
					
						
							|  |  |  |         pattern_parts = path_pattern.parts[::-1] | 
					
						
							|  |  |  |         if not pattern_parts: | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |             raise ValueError("empty pattern") | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |         if len(path_parts) < len(pattern_parts): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         if len(path_parts) > len(pattern_parts) and path_pattern.anchor: | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2024-04-10 20:43:07 +01:00
										 |  |  |         globber = self._globber(sep, case_sensitive) | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |         for path_part, pattern_part in zip(path_parts, pattern_parts): | 
					
						
							| 
									
										
										
										
											2024-04-10 20:43:07 +01:00
										 |  |  |             match = globber.compile(pattern_part) | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |             if match(path_part) is None: | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def full_match(self, pattern, *, case_sensitive=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return True if this path matches the given glob-style pattern. The | 
					
						
							|  |  |  |         pattern is matched against the entire path. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if not isinstance(pattern, PurePathBase): | 
					
						
							|  |  |  |             pattern = self.with_segments(pattern) | 
					
						
							|  |  |  |         if case_sensitive is None: | 
					
						
							| 
									
										
										
										
											2024-03-31 19:14:48 +01:00
										 |  |  |             case_sensitive = _is_case_sensitive(self.parser) | 
					
						
							| 
									
										
										
										
											2024-04-10 20:43:07 +01:00
										 |  |  |         globber = self._globber(pattern.parser.sep, case_sensitive, recursive=True) | 
					
						
							|  |  |  |         match = globber.compile(pattern._pattern_str) | 
					
						
							| 
									
										
										
										
											2024-01-26 01:12:46 +00:00
										 |  |  |         return match(self._pattern_str) is not None | 
					
						
							| 
									
										
										
										
											2023-05-30 21:18:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
											
												GH-110109: Add `pathlib._PurePathBase` (#110670)
Add private `pathlib._PurePathBase` class: a private superclass of both `PurePath` and `_PathBase`. Unlike `PurePath`, it does not define any of these special methods: `__fspath__`, `__bytes__`, `__reduce__`, `__hash__`, `__eq__`, `__lt__`, `__le__`, `__gt__`, `__ge__`. Its initializer and path joining methods accept only strings, not os.PathLike objects more broadly.
This is important for supporting *virtual paths*: user subclasses of `_PathBase` that provide access to archive files, FTP servers, etc. In these classes, the above methods should be implemented by users only as appropriate, with due consideration for the hash/equality of any backing objects, such as file objects or sockets.
											
										 
											2023-12-08 17:39:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 15:07:40 +00:00
										 |  |  | class PathBase(PurePathBase): | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |     """Base class for concrete path objects.
 | 
					
						
							| 
									
										
										
										
											2018-02-19 08:36:32 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |     This class provides dummy implementations for many methods that derived | 
					
						
							|  |  |  |     classes can override selectively; the default implementations raise | 
					
						
							|  |  |  |     UnsupportedOperation. The most basic methods, such as stat() and open(), | 
					
						
							|  |  |  |     directly raise UnsupportedOperation; these basic methods are called by | 
					
						
							|  |  |  |     other methods such as is_dir() and read_text(). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The Path class derives this class to implement local filesystem paths. | 
					
						
							|  |  |  |     Users may derive their own classes to implement virtual filesystem paths, | 
					
						
							|  |  |  |     such as paths in archive files or on remote storage systems. | 
					
						
							| 
									
										
										
										
											2018-02-19 08:36:32 +09:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 01:26:37 +01:00
										 |  |  |     __slots__ = () | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-01 16:14:02 +01:00
										 |  |  |     @classmethod | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |     def _unsupported_msg(cls, attribute): | 
					
						
							|  |  |  |         return f"{cls.__name__}.{attribute} is unsupported" | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |     def stat(self, *, follow_symlinks=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return the result of the stat() system call on this path, like | 
					
						
							|  |  |  |         os.stat() does. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('stat()')) | 
					
						
							| 
									
										
										
										
											2023-04-03 19:57:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |     # Convenience functions for querying the stat results | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |     def exists(self, *, follow_symlinks=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Whether this path exists. | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |         This method normally follows symlinks; to check whether a symlink exists, | 
					
						
							|  |  |  |         add the argument follow_symlinks=False. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.stat(follow_symlinks=follow_symlinks) | 
					
						
							| 
									
										
										
										
											2024-05-14 18:53:15 +01:00
										 |  |  |         except (OSError, ValueError): | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |             return False | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-26 17:58:17 +01:00
										 |  |  |     def is_dir(self, *, follow_symlinks=True): | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Whether this path is a directory. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2023-06-26 17:58:17 +01:00
										 |  |  |             return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode) | 
					
						
							| 
									
										
										
										
											2024-05-14 18:53:15 +01:00
										 |  |  |         except (OSError, ValueError): | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-26 17:58:17 +01:00
										 |  |  |     def is_file(self, *, follow_symlinks=True): | 
					
						
							| 
									
										
										
										
											2015-01-12 21:03:41 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |         Whether this path is a regular file (also True for symlinks pointing | 
					
						
							|  |  |  |         to regular files). | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2023-06-26 17:58:17 +01:00
										 |  |  |             return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode) | 
					
						
							| 
									
										
										
										
											2024-05-14 18:53:15 +01:00
										 |  |  |         except (OSError, ValueError): | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_symlink(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Whether this path is a symbolic link. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-11-29 21:03:39 +00:00
										 |  |  |             return S_ISLNK(self.stat(follow_symlinks=False).st_mode) | 
					
						
							| 
									
										
										
										
											2024-05-14 18:53:15 +01:00
										 |  |  |         except (OSError, ValueError): | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 20:03:11 +01:00
										 |  |  |     def _ensure_different_file(self, other_path): | 
					
						
							| 
									
										
										
										
											2024-06-14 17:15:49 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-08-23 20:03:11 +01:00
										 |  |  |         Raise OSError(EINVAL) if both paths refer to the same file. | 
					
						
							| 
									
										
										
										
											2024-06-14 17:15:49 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-12-11 00:09:55 +00:00
										 |  |  |         pass | 
					
						
							| 
									
										
										
										
											2024-08-23 20:03:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _ensure_distinct_path(self, other_path): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Raise OSError(EINVAL) if the other path is within this path. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # Note: there is no straightforward, foolproof algorithm to determine | 
					
						
							|  |  |  |         # if one directory is within another (a particularly perverse example | 
					
						
							|  |  |  |         # would be a single network share mounted in one location via NFS, and | 
					
						
							|  |  |  |         # in another location via CIFS), so we simply checks whether the | 
					
						
							|  |  |  |         # other path is lexically equal to, or within, this path. | 
					
						
							|  |  |  |         if self == other_path: | 
					
						
							|  |  |  |             err = OSError(EINVAL, "Source and target are the same path") | 
					
						
							|  |  |  |         elif self in other_path.parents: | 
					
						
							|  |  |  |             err = OSError(EINVAL, "Source path is a parent of target path") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         err.filename = str(self) | 
					
						
							|  |  |  |         err.filename2 = str(other_path) | 
					
						
							|  |  |  |         raise err | 
					
						
							| 
									
										
										
										
											2024-06-14 17:15:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |     def open(self, mode='r', buffering=-1, encoding=None, | 
					
						
							|  |  |  |              errors=None, newline=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-05-02 00:37:12 -05:00
										 |  |  |         Open the file pointed to by this path and return a file object, as | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |         the built-in open() function does. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('open()')) | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def read_bytes(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Open the file in bytes mode, read it, and close the file. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-08-16 13:52:41 -07:00
										 |  |  |         with self.open(mode='rb', buffering=0) as f: | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |             return f.read() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-22 07:32:38 +09:00
										 |  |  |     def read_text(self, encoding=None, errors=None, newline=None): | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Open the file in text mode, read it, and close the file. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-11-22 07:32:38 +09:00
										 |  |  |         with self.open(mode='r', encoding=encoding, errors=errors, newline=newline) as f: | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |             return f.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def write_bytes(self, data): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Open the file in bytes mode, write to it, and close the file. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # type-check for the buffer interface before truncating the file | 
					
						
							|  |  |  |         view = memoryview(data) | 
					
						
							|  |  |  |         with self.open(mode='wb') as f: | 
					
						
							|  |  |  |             return f.write(view) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def write_text(self, data, encoding=None, errors=None, newline=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Open the file in text mode, write to it, and close the file. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if not isinstance(data, str): | 
					
						
							|  |  |  |             raise TypeError('data must be str, not %s' % | 
					
						
							|  |  |  |                             data.__class__.__name__) | 
					
						
							|  |  |  |         with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: | 
					
						
							|  |  |  |             return f.write(data) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-05 21:39:43 +00:00
										 |  |  |     def _scandir(self): | 
					
						
							|  |  |  |         """Yield os.DirEntry-like objects of the directory contents.
 | 
					
						
							| 
									
										
										
										
											2024-11-01 01:19:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         The children are yielded in arbitrary order, and the | 
					
						
							|  |  |  |         special entries '.' and '..' are not included. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-12-05 21:39:43 +00:00
										 |  |  |         import contextlib | 
					
						
							|  |  |  |         return contextlib.nullcontext(self.iterdir()) | 
					
						
							| 
									
										
										
										
											2024-11-01 01:19:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |     def iterdir(self): | 
					
						
							| 
									
										
										
										
											2022-11-10 01:05:07 +03:00
										 |  |  |         """Yield path objects of the directory contents.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The children are yielded in arbitrary order, and the | 
					
						
							|  |  |  |         special entries '.' and '..' are not included. | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-12-05 21:39:43 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('iterdir()')) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 20:43:07 +01:00
										 |  |  |     def _glob_selector(self, parts, case_sensitive, recurse_symlinks): | 
					
						
							|  |  |  |         if case_sensitive is None: | 
					
						
							|  |  |  |             case_sensitive = _is_case_sensitive(self.parser) | 
					
						
							| 
									
										
										
										
											2024-04-12 22:19:21 +01:00
										 |  |  |             case_pedantic = False | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # The user has expressed a case sensitivity choice, but we don't | 
					
						
							|  |  |  |             # know the case sensitivity of the underlying filesystem, so we | 
					
						
							|  |  |  |             # must use scandir() for everything, including non-wildcard parts. | 
					
						
							|  |  |  |             case_pedantic = True | 
					
						
							| 
									
										
										
										
											2024-05-07 01:32:48 +01:00
										 |  |  |         recursive = True if recurse_symlinks else _no_recurse_symlinks | 
					
						
							| 
									
										
										
										
											2024-04-12 22:19:21 +01:00
										 |  |  |         globber = self._globber(self.parser.sep, case_sensitive, case_pedantic, recursive) | 
					
						
							| 
									
										
										
										
											2024-04-10 20:43:07 +01:00
										 |  |  |         return globber.selector(parts) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 19:51:54 +01:00
										 |  |  |     def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=True): | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """Iterate over this subtree and yield all existing files (of any
 | 
					
						
							| 
									
										
										
										
											2019-02-11 11:47:09 +01:00
										 |  |  |         kind, including directories) matching the given relative pattern. | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-20 02:10:25 +00:00
										 |  |  |         if not isinstance(pattern, PurePathBase): | 
					
						
							|  |  |  |             pattern = self.with_segments(pattern) | 
					
						
							| 
									
										
										
										
											2024-04-10 20:43:07 +01:00
										 |  |  |         anchor, parts = pattern._stack | 
					
						
							|  |  |  |         if anchor: | 
					
						
							|  |  |  |             raise NotImplementedError("Non-relative patterns are unsupported") | 
					
						
							|  |  |  |         select = self._glob_selector(parts, case_sensitive, recurse_symlinks) | 
					
						
							| 
									
										
										
										
											2024-04-14 00:08:03 +01:00
										 |  |  |         return select(self) | 
					
						
							| 
									
										
										
										
											2013-11-22 17:38:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-05 19:51:54 +01:00
										 |  |  |     def rglob(self, pattern, *, case_sensitive=None, recurse_symlinks=True): | 
					
						
							| 
									
										
										
										
											2024-01-05 21:41:19 +00:00
										 |  |  |         """Recursively yield all existing files (of any kind, including
 | 
					
						
							|  |  |  |         directories) matching the given relative pattern, anywhere in | 
					
						
							|  |  |  |         this subtree. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-20 02:10:25 +00:00
										 |  |  |         if not isinstance(pattern, PurePathBase): | 
					
						
							|  |  |  |             pattern = self.with_segments(pattern) | 
					
						
							|  |  |  |         pattern = '**' / pattern | 
					
						
							| 
									
										
										
										
											2024-04-05 19:51:54 +01:00
										 |  |  |         return self.glob(pattern, case_sensitive=case_sensitive, recurse_symlinks=recurse_symlinks) | 
					
						
							| 
									
										
										
										
											2024-01-05 21:41:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  |     def walk(self, top_down=True, on_error=None, follow_symlinks=False): | 
					
						
							|  |  |  |         """Walk the directory tree from this directory, similar to os.walk().""" | 
					
						
							| 
									
										
										
										
											2024-05-29 21:51:04 +01:00
										 |  |  |         paths = [self] | 
					
						
							|  |  |  |         while paths: | 
					
						
							|  |  |  |             path = paths.pop() | 
					
						
							|  |  |  |             if isinstance(path, tuple): | 
					
						
							|  |  |  |                 yield path | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             dirnames = [] | 
					
						
							|  |  |  |             filenames = [] | 
					
						
							|  |  |  |             if not top_down: | 
					
						
							|  |  |  |                 paths.append((path, dirnames, filenames)) | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2024-12-05 21:39:43 +00:00
										 |  |  |                 with path._scandir() as entries: | 
					
						
							| 
									
										
										
										
											2024-11-01 18:52:00 +00:00
										 |  |  |                     for entry in entries: | 
					
						
							|  |  |  |                         name = entry.name | 
					
						
							|  |  |  |                         try: | 
					
						
							|  |  |  |                             if entry.is_dir(follow_symlinks=follow_symlinks): | 
					
						
							|  |  |  |                                 if not top_down: | 
					
						
							|  |  |  |                                     paths.append(path.joinpath(name)) | 
					
						
							|  |  |  |                                 dirnames.append(name) | 
					
						
							|  |  |  |                             else: | 
					
						
							|  |  |  |                                 filenames.append(name) | 
					
						
							|  |  |  |                         except OSError: | 
					
						
							|  |  |  |                             filenames.append(name) | 
					
						
							| 
									
										
										
										
											2024-05-29 21:51:04 +01:00
										 |  |  |             except OSError as error: | 
					
						
							|  |  |  |                 if on_error is not None: | 
					
						
							|  |  |  |                     on_error(error) | 
					
						
							|  |  |  |                 if not top_down: | 
					
						
							|  |  |  |                     while not isinstance(paths.pop(), tuple): | 
					
						
							|  |  |  |                         pass | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if top_down: | 
					
						
							|  |  |  |                 yield path, dirnames, filenames | 
					
						
							|  |  |  |                 paths += [path.joinpath(d) for d in reversed(dirnames)] | 
					
						
							| 
									
										
										
										
											2023-05-07 20:07:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |     def expanduser(self): | 
					
						
							|  |  |  |         """ Return a new path with expanded ~ and ~user constructs
 | 
					
						
							|  |  |  |         (as returned by os.path.expanduser) | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('expanduser()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def readlink(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return the path to which the symbolic link points. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('readlink()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def symlink_to(self, target, target_is_directory=False): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Make this path a symlink pointing to the target path. | 
					
						
							|  |  |  |         Note the order of arguments (link, target) is the reverse of os.symlink. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('symlink_to()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |     def _symlink_to_target_of(self, link): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Make this path a symlink with the same target as the given link. This | 
					
						
							|  |  |  |         is used by copy(). | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.symlink_to(link.readlink()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |     def hardlink_to(self, target): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Make this path a hard link pointing to the same file as *target*. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Note the order of arguments (self, target) is the reverse of os.link's. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('hardlink_to()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def touch(self, mode=0o666, exist_ok=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Create this file with the given access mode, if it doesn't exist. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('touch()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def mkdir(self, mode=0o777, parents=False, exist_ok=False): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Create a new directory at this given path. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('mkdir()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-06 17:18:39 +01:00
										 |  |  |     # Metadata keys supported by this path type. | 
					
						
							|  |  |  |     _readable_metadata = _writable_metadata = frozenset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _read_metadata(self, keys=None, *, follow_symlinks=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Returns path metadata as a dict with string keys. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         raise UnsupportedOperation(self._unsupported_msg('_read_metadata()')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _write_metadata(self, metadata, *, follow_symlinks=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Sets path metadata from the given dict with string keys. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         raise UnsupportedOperation(self._unsupported_msg('_write_metadata()')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _copy_metadata(self, target, *, follow_symlinks=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Copies metadata (permissions, timestamps, etc) from this path to target. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # Metadata types supported by both source and target. | 
					
						
							|  |  |  |         keys = self._readable_metadata & target._writable_metadata | 
					
						
							|  |  |  |         if keys: | 
					
						
							|  |  |  |             metadata = self._read_metadata(keys, follow_symlinks=follow_symlinks) | 
					
						
							|  |  |  |             target._write_metadata(metadata, follow_symlinks=follow_symlinks) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |     def _copy_file(self, target): | 
					
						
							| 
									
										
										
										
											2024-06-14 17:15:49 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |         Copy the contents of this file to the given target. | 
					
						
							| 
									
										
										
										
											2024-06-14 17:15:49 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-08-23 20:03:11 +01:00
										 |  |  |         self._ensure_different_file(target) | 
					
						
							| 
									
										
										
										
											2024-06-14 17:15:49 +01:00
										 |  |  |         with self.open('rb') as source_f: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with target.open('wb') as target_f: | 
					
						
							|  |  |  |                     copyfileobj(source_f, target_f) | 
					
						
							|  |  |  |             except IsADirectoryError as e: | 
					
						
							|  |  |  |                 if not target.exists(): | 
					
						
							|  |  |  |                     # Raise a less confusing exception. | 
					
						
							|  |  |  |                     raise FileNotFoundError( | 
					
						
							|  |  |  |                         f'Directory does not exist: {target}') from e | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     raise | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |     def copy(self, target, *, follow_symlinks=True, dirs_exist_ok=False, | 
					
						
							| 
									
										
										
										
											2024-08-26 17:05:34 +01:00
										 |  |  |              preserve_metadata=False): | 
					
						
							| 
									
										
										
										
											2024-06-23 22:01:12 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |         Recursively copy this file or directory tree to the given destination. | 
					
						
							| 
									
										
										
										
											2024-06-23 22:01:12 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         if not isinstance(target, PathBase): | 
					
						
							|  |  |  |             target = self.with_segments(target) | 
					
						
							| 
									
										
										
										
											2024-08-26 17:05:34 +01:00
										 |  |  |         self._ensure_distinct_path(target) | 
					
						
							| 
									
										
										
										
											2024-06-23 22:01:12 +01:00
										 |  |  |         stack = [(self, target)] | 
					
						
							|  |  |  |         while stack: | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |             src, dst = stack.pop() | 
					
						
							| 
									
										
										
										
											2024-08-26 17:05:34 +01:00
										 |  |  |             if not follow_symlinks and src.is_symlink(): | 
					
						
							|  |  |  |                 dst._symlink_to_target_of(src) | 
					
						
							|  |  |  |                 if preserve_metadata: | 
					
						
							|  |  |  |                     src._copy_metadata(dst, follow_symlinks=False) | 
					
						
							|  |  |  |             elif src.is_dir(): | 
					
						
							|  |  |  |                 children = src.iterdir() | 
					
						
							|  |  |  |                 dst.mkdir(exist_ok=dirs_exist_ok) | 
					
						
							|  |  |  |                 stack.extend((child, dst.joinpath(child.name)) | 
					
						
							|  |  |  |                              for child in children) | 
					
						
							|  |  |  |                 if preserve_metadata: | 
					
						
							|  |  |  |                     src._copy_metadata(dst) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 src._copy_file(dst) | 
					
						
							|  |  |  |                 if preserve_metadata: | 
					
						
							|  |  |  |                     src._copy_metadata(dst) | 
					
						
							| 
									
										
										
										
											2024-08-11 22:43:18 +01:00
										 |  |  |         return target | 
					
						
							| 
									
										
										
										
											2024-06-23 22:01:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-26 14:14:23 +01:00
										 |  |  |     def copy_into(self, target_dir, *, follow_symlinks=True, | 
					
						
							| 
									
										
										
										
											2024-08-26 17:05:34 +01:00
										 |  |  |                   dirs_exist_ok=False, preserve_metadata=False): | 
					
						
							| 
									
										
										
										
											2024-08-26 14:14:23 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Copy this file or directory tree into the given existing directory. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         name = self.name | 
					
						
							|  |  |  |         if not name: | 
					
						
							|  |  |  |             raise ValueError(f"{self!r} has an empty name") | 
					
						
							|  |  |  |         elif isinstance(target_dir, PathBase): | 
					
						
							|  |  |  |             target = target_dir / name | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             target = self.with_segments(target_dir, name) | 
					
						
							|  |  |  |         return self.copy(target, follow_symlinks=follow_symlinks, | 
					
						
							|  |  |  |                          dirs_exist_ok=dirs_exist_ok, | 
					
						
							| 
									
										
										
										
											2024-08-26 17:05:34 +01:00
										 |  |  |                          preserve_metadata=preserve_metadata) | 
					
						
							| 
									
										
										
										
											2024-08-26 14:14:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-08 18:45:09 +00:00
										 |  |  |     def _delete(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Delete this file or directory (including all sub-directories). | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         raise UnsupportedOperation(self._unsupported_msg('_delete()')) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-25 16:51:51 +01:00
										 |  |  |     def move(self, target): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Recursively move this file or directory tree to the given destination. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         target = self.copy(target, follow_symlinks=False, preserve_metadata=True) | 
					
						
							| 
									
										
										
										
											2024-08-26 16:26:34 +01:00
										 |  |  |         self._delete() | 
					
						
							| 
									
										
										
										
											2024-08-25 16:51:51 +01:00
										 |  |  |         return target | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-26 14:14:23 +01:00
										 |  |  |     def move_into(self, target_dir): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Move this file or directory tree into the given existing directory. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         name = self.name | 
					
						
							|  |  |  |         if not name: | 
					
						
							|  |  |  |             raise ValueError(f"{self!r} has an empty name") | 
					
						
							|  |  |  |         elif isinstance(target_dir, PathBase): | 
					
						
							|  |  |  |             target = target_dir / name | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             target = self.with_segments(target_dir, name) | 
					
						
							|  |  |  |         return self.move(target) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |     def chmod(self, mode, *, follow_symlinks=True): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Change the permissions of the path, like os.chmod(). | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('chmod()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def lchmod(self, mode): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Like chmod(), except if the path points to a symlink, the symlink's | 
					
						
							|  |  |  |         permissions are changed, rather than its target's. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.chmod(mode, follow_symlinks=False) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 20:42:01 +01:00
										 |  |  |     def owner(self, *, follow_symlinks=True): | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Return the login name of the file owner. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('owner()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 20:42:01 +01:00
										 |  |  |     def group(self, *, follow_symlinks=True): | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Return the group name of the file gid. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('group()')) | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-01 16:14:02 +01:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_uri(cls, uri): | 
					
						
							|  |  |  |         """Return a new path from the given 'file' URI.""" | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(cls._unsupported_msg('from_uri()')) | 
					
						
							| 
									
										
										
										
											2023-10-01 16:14:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-30 15:45:01 +01:00
										 |  |  |     def as_uri(self): | 
					
						
							|  |  |  |         """Return the path as a URI.""" | 
					
						
							| 
									
										
										
										
											2024-01-31 00:38:01 +00:00
										 |  |  |         raise UnsupportedOperation(self._unsupported_msg('as_uri()')) |