Edit on GitHub

gpath

GPath is a robust, generalised abstract file path that provides path manipulations independent from the local environment, maximising cross-platform compatibility.

 1"""
 2	GPath is a robust, generalised abstract file path that provides path manipulations independent from the local environment, maximising cross-platform compatibility.
 3"""
 4
 5
 6__version__ = '0.5.1'
 7
 8from . import platform, render
 9from ._gpath import GPath, GPathLike
10
11__all__ = ('GPath', 'GPathLike', 'platform', 'render')
class GPath(Hashable, Sized, Iterable, render.Renderable):
  81class GPath(Hashable, Sized, Iterable, render.Renderable):
  82	"""
  83		An immutable generalised abstract file path that has no dependency on any real filesystem.
  84
  85		The path can be manipulated on a system that is different from where it originated, notably including systems with a different operating system, and it can represent file paths on a system other than local. Examples where this is useful include remote management of servers and when cross-compiling source code for a different platform.
  86
  87		Since GPath objects are immutable, all operations return a new instance. The path is always stored in a normalised state, and is always treated as case sensitive.
  88
  89		The path can be rendered as a string using <code>str(<var>g</var>)</code>, which will use `/` as the path separator if possible to maximise cross-platform compatibility.
  90	"""
  91
  92	__slots__ = (
  93		'_parts',
  94		'_root',
  95		'_drive',
  96		'_parent_level',
  97		'_platform',
  98		'_encoding',
  99	)
 100
 101
 102	def __init__(self,
 103		path: Union[str, bytes, os.PathLike, GPath, None]="",
 104		platform: Optional[Union[str, Platform]]=None,
 105		encoding: Optional[str]=None,
 106	):
 107		"""
 108			Initialise a normalised and generalised abstract file path, possibly by copying an existing GPath object.
 109
 110			Parameters
 111			----------
 112			`path`
 113			: path-like object representing a (possibly unnormalised) file path, or a GPath object to be copied
 114
 115			`platform`
 116			: interpret `path` as originating from a specific platform. This is usually not required for normal file paths on Windows, Linux or macOS, and is needed only for edge cases (see [compatibility](https://github.com/yushiyangk/gpath#compatibility) in the readme). If `path` is a GPath, this argument has no effect. The platform name should be one of the keys in `gpath.platform.platform_names`. If specified, the platform will propagate to new GPaths returned by operations on this GPath; for binary operations on two GPaths, the platform specified by the left operand will be propagated. See also the static methods `from_*()`.
 117
 118			`encoding`
 119			: the text encoding that should be used to decode paths given as bytes-like objects; if not specified, `'utf_8'` will be used by default. The encoding name should be one of the standard Python text encodings, as listed in the `codecs` module of the standard library. If specified, the encoding will propagate to new GPaths returned by operations on this GPath; for binary operations on two GPaths, the encoding specified by the left operand will be propagated.
 120
 121			Raises
 122			------
 123			`ValueError` if `path` is an invalid GPath
 124
 125			Examples
 126			--------
 127			```python
 128			GPath("/")
 129			GPath("/usr/bin")
 130			GPath("C:/Program Files")
 131			```
 132		"""
 133
 134		self._parts: tuple[str, ...] = tuple()  # root- or parent- relative path
 135		self._root: bool = False
 136		self._drive: str = ""
 137		self._parent_level: int = 0
 138
 139		self._platform: Union[Platform, None] = Platform.from_str(platform) if isinstance(platform, str) else platform
 140		self._encoding: Union[str, None] = encoding
 141
 142		if isinstance(path, GPath):
 143			path._validate()
 144			self._parts = path._parts
 145			self._root = path._root
 146			self._drive = path._drive
 147			self._parent_level = path._parent_level
 148
 149			self._platform = path._platform if self._platform is None else self._platform
 150			self._encoding = path._encoding if self._encoding is None else self._encoding
 151			return
 152
 153		if path is None or path == "":
 154			return
 155
 156		path = os.fspath(path)
 157
 158		if isinstance(path, bytes):
 159			if self._encoding is None:
 160				path = path.decode(DEFAULT_ENCODING)
 161			else:
 162				path = path.decode(self._encoding)
 163
 164		path = cast(str, path)
 165
 166		if self._platform is None:
 167			platform = Platform.GENERIC
 168		else:
 169			platform = self._platform
 170
 171		if platform == Platform.POSIX:
 172			for root in _rules.posix_rules.roots:
 173				if path.startswith(root):
 174					self._root = True
 175					break
 176
 177			if self._root:
 178				rootless_path = path[1:]
 179			else:
 180				rootless_path = path
 181
 182			parts = _split_relative(rootless_path, delimiters=_rules.posix_rules.separators)
 183
 184		elif platform == Platform.WINDOWS:
 185			if len(path) >= 2 and path[1] in _rules.windows_rules.drive_postfixes:
 186				self._drive = path[0]
 187				driveless_path = path[2:]
 188			else:
 189				driveless_path = path
 190
 191			for root in _rules.windows_rules.roots:
 192				if driveless_path.startswith(root):
 193					self._root = True
 194					break
 195
 196			if self._root:
 197				rootless_path = driveless_path[1:]
 198			else:
 199				rootless_path = driveless_path
 200
 201			parts = _split_relative(rootless_path, delimiters=_rules.windows_rules.separators)
 202
 203		else:
 204			if len(path) >= 2 and path[1] in _rules.generic_rules.drive_postfixes:
 205				self._drive = path[0]
 206				driveless_path = path[2:]
 207			else:
 208				driveless_path = path
 209
 210			for root in _rules.generic_rules.roots:
 211				if driveless_path.startswith(root):
 212					self._root = True
 213					break
 214
 215			if self._root:
 216				rootless_path = driveless_path[1:]
 217			else:
 218				rootless_path = driveless_path
 219
 220			parts = _split_relative(rootless_path, delimiters=_rules.generic_rules.separators)
 221
 222
 223		parts = _normalise_relative(parts)
 224		parent_level = 0
 225		while parent_level < len(parts) and parts[parent_level] in _rules.generic_rules.parent_indicators:
 226			parent_level += 1
 227		self._parts = tuple(parts[parent_level:])
 228		if self._root == False:
 229			self._parent_level = parent_level
 230
 231
 232	@property
 233	def named_parts(self) -> list[str]:
 234		"""
 235			Read-only named components of the path, not including the filesystem root, drive name, or any parent directories
 236
 237			Examples
 238			--------
 239			```python
 240			GPath("usr/local/bin").named_parts     # ["usr", "local", "bin"]
 241			GPath("../../Documents").named_parts   # ["Documents"]
 242			GPath("/usr/bin").named_parts          # ["usr", "bin"]
 243			GPath("C:/Program Files").named_parts  # ["Program Files"]
 244			```
 245		"""
 246		return list(self._parts)
 247
 248	@property
 249	def relative_parts(self) -> list[str]:
 250		"""
 251			Read-only relative components of the path, not including the filesystem root or drive name, including one item for each level of parent directory
 252
 253			Examples
 254			--------
 255			```python
 256			GPath("usr/local/bin").relative_parts     # ["usr", "local", "bin"]
 257			GPath("../../Documents").relative_parts   # ["..", "..", "Documents"]
 258			GPath("/usr/bin").relative_parts          # ["usr", "bin"]
 259			GPath("C:/Program Files").relative_parts  # ["Program Files"]
 260			```
 261		"""
 262		return self.parent_parts + list(self._parts)
 263
 264	@property
 265	def absolute(self) -> bool:
 266		"""
 267			Read-only flag for whether the path is an absolute path
 268
 269			Examples
 270			--------
 271			```python
 272			GPath("/").absolute                # True
 273			GPath("C:/Windows").absolute       # True
 274			GPath("local/bin").absolute        # False
 275			GPath("../../Documents").absolute  # False
 276			```
 277		"""
 278		return self._root
 279
 280	@property
 281	def root(self) -> bool:
 282		"""
 283			Read-only flag for whether the path is exactly the root of the filesystem
 284
 285			Examples
 286			--------
 287			```python
 288			GPath("/").root                # True
 289			GPath("C:/").root              # True
 290			GPath("/usr/bin").root         # False
 291			GPath("C:/Windows").root       # False
 292			GPath("../../Documents").root  # False
 293			```
 294		"""
 295		return self._root and len(self._parts) == 0
 296
 297	@property
 298	def drive(self) -> str:
 299		"""
 300			Read-only drive name
 301
 302			Examples
 303			--------
 304			```python
 305			GPath("C:/Windows").drive       # "C:"
 306			GPath("/usr/bin").drive         # ""
 307			GPath("../../Documents").drive  # ""
 308			```
 309		"""
 310		return self._drive
 311
 312	@property
 313	def parent_level(self) -> int:
 314		"""
 315			Read-only number of levels of parent directories that the path is relative to, which may be 0
 316
 317			Examples
 318			--------
 319			```python
 320			GPath("../../Documents").parent_level  # 2
 321			GPath("usr/local/bin").parent_level    # 0
 322			```
 323		"""
 324		return self._parent_level
 325
 326	@property
 327	def parent_parts(self) -> list[str]:
 328		"""
 329			Read-only path components representing a parent directory that it is relative to, if any, with one item for each level of parent directory
 330
 331			Examples
 332			--------
 333			```python
 334			GPath("../../Documents").parent_parts  # ["..", ".."]
 335			GPath("usr/local/bin").parent_parts    # []
 336			```
 337		"""
 338		return [_rules.generic_rules.parent_indicators[0] for i in range(self._parent_level)]
 339
 340	@property
 341	def encoding(self) -> Union[str, None]:
 342		"""
 343			Read-only encoding used to decode other paths that are given as bytes-like objects, or None if the default should be used
 344		"""
 345		return self._encoding
 346
 347	@property
 348	def platform(self) -> Union[str, None]:
 349		"""
 350			Read-only platform that other non-GPath operands should be interepreted as, or None if the default should be used
 351		"""
 352		return str(self._platform) if self._platform is not None else None
 353
 354
 355	@staticmethod
 356	def from_posix(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
 357		"""
 358			Initialise a GPath that originates from a POSIX-like operating system, or copy a GPath such that any future non-GPath operands would be interpreted as originating from a POSIX-like operating system.
 359
 360			See `__init__()` for details.
 361
 362			Equivalent to `GPath(path, platform='posix')`
 363			```
 364		"""
 365		return GPath(path, platform=Platform.POSIX, encoding=encoding)
 366
 367	@staticmethod
 368	def from_linux(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
 369		"""
 370			Alias of `from_posix()`
 371		"""
 372		return GPath.from_posix(path, encoding=encoding)
 373
 374	@staticmethod
 375	def from_macos(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
 376		"""
 377			Alias of `from_posix()`
 378		"""
 379		return GPath.from_posix(path, encoding=encoding)
 380
 381
 382	@staticmethod
 383	def from_windows(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
 384		"""
 385			Initialise a GPath that originates from a Windows operating system, or copy a GPath such that any future non-GPath operands would be interpreted as originating from a Windows operating system.
 386
 387			See `__init__()` for details.
 388
 389			Equivalent to `GPath(path, platform='windows')`
 390			```
 391		"""
 392		return GPath(path, platform=Platform.WINDOWS, encoding=encoding)
 393
 394
 395	#@overload
 396	#@staticmethod
 397	#def partition(paths: Iterable[GPathLike], /, *, allow_current, allow_parents, platform, encoding) -> dict[GPath, list[GPath]]:
 398	#	...
 399	#@overload
 400	#@staticmethod
 401	#def partition(*paths: GPathLike, allow_current, allow_parents, platform, encoding) -> dict[GPath, list[GPath]]:
 402	#	...
 403	@staticmethod
 404	def partition(
 405		*paths,
 406		allow_current: bool=True,
 407		allow_parents: bool=True,
 408		platform: Optional[Union[str, Platform]]=None,
 409		encoding: Optional[str]=None,
 410	) -> dict[GPath, list[GPath]]:
 411		"""
 412			Partition a collection of paths based on shared common base paths such that each path belongs to one partition.
 413
 414			For each partition, return a list of relative paths from the base path of that partition to each corresponding input path within that partition, unless `allow_parents` is True (see below). If the input collection is ordered, the output order is preserved within each partition. If the input collection contains duplicates, the corresponding output lists will as well.
 415
 416			The number of partitions is minimised by merging partitions as much as possible, so that each partition represents the highest possible level base path. Two partitions can no longer be merged when there is no common base path between them, as determined by `common_with()`. This method takes the same optional arguments as `common_with()`, with the same default values.
 417
 418			Parameters
 419			----------
 420			`paths: Iterable[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
 421			: the paths to be partitioned, which can be given as either a list-like object or as variadic arguments
 422
 423			`allow_current`
 424			: whether non-parent relative paths with no shared components should be considered to have a common base path (see `common_with()`)
 425
 426			`allow_parents`
 427			: whether paths that are relative to different levels of parent directories should be considered to have a common base path (see `common_with()`). **Warning**: when set to True, the output lists for each partition are invalidated, and explicitly set to empty. This is because it is not possible in general to obtain a relative path from the base path to its members if the base path is a parent directory of a higher level than the member (see `relpath_from()`). This  option should be True if and only if the list of members in each partition are not of interest; in most cases False is more appropriate.
 428
 429			`​platform`
 430			: the originating platform that should be assumed when interpreting non-GPath objects in `paths`, if any (see `__init__()`).
 431
 432			`​encoding`
 433			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
 434
 435			Returns
 436			-------
 437			a dictionary that maps the common base path of each partition to a list of relative paths
 438
 439			Raises
 440			------
 441			  `ValueError`
 442			  if any of the GPaths are invalid
 443
 444			Examples
 445			--------
 446			```python
 447			partitions = GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")
 448
 449			assert partitions == {
 450				GPath("/usr")      : [GPath("bin"), GPath("local")],
 451				GPath("../../doc") : [GPath("")],
 452				GPath("C:/")       : [GPath("Windows"), GPath("Program Files")],
 453			}
 454			```
 455		"""
 456		flattened_paths: list[GPathLike] = []
 457		for path_or_list in paths:
 458			if _is_gpathlike(path_or_list):
 459				flattened_paths.append(path_or_list)
 460			else:
 461				flattened_paths.extend(path_or_list)
 462		gpaths = [path if isinstance(path, GPath) else GPath(path, encoding=encoding, platform=platform) for path in flattened_paths]
 463
 464		partition_map = {}
 465		if len(gpaths) > 0:
 466			if allow_parents == True:
 467				partition_map[gpaths[0]] = []
 468			else:
 469				partition_map[gpaths[0]] = [gpaths[0]]
 470
 471		for path in gpaths[1:]:
 472			partition_found = False
 473			for partition in partition_map:
 474				candidate_common = partition.common_with(path, allow_current=allow_current, allow_parents=allow_parents)
 475				if candidate_common is not None:
 476					partition_found = True
 477					if candidate_common != partition:
 478						partition_map[candidate_common] = partition_map[partition]
 479						del partition_map[partition]
 480					if allow_parents == False:
 481						partition_map[candidate_common].append(path)
 482					break
 483			if not partition_found:
 484				if allow_parents == True:
 485					partition_map[path] = []
 486				else:
 487					partition_map[path] = [path]
 488
 489		for partition, path_list in partition_map.items():
 490			partition_map[partition] = [path.subpath_from(partition) for path in path_list]
 491
 492		return partition_map
 493
 494
 495	#@overload
 496	#@staticmethod
 497	#def join(paths: Iterable[GPathLike], /, *, platform, encoding) -> GPath:
 498	#	...
 499	#@overload
 500	#@staticmethod
 501	#def join(*paths: GPathLike, platform, encoding) -> GPath:
 502	#	...
 503	@staticmethod
 504	def join(*paths, platform: Optional[Union[str, Platform]]=None, encoding: Optional[str]=None) -> GPath:
 505		"""
 506			Join a sequence of paths into a single path. Apart from the first item in the sequence, all subsequent paths should be relative paths and any absolute paths will be ignored.
 507
 508			Parameters
 509			----------
 510			`paths`: `Sequence[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
 511			: the paths to be combined, which can be given as either a list-like object or as variadic arguments
 512
 513			`​platform`
 514			: the originating platform that should be assumed when interpreting non-GPath objects in `paths`, if any (see `__init__()`).
 515
 516			`​encoding`
 517			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
 518
 519			Returns
 520			-------
 521			the combined path
 522
 523			Raises
 524			------
 525			`ValueError` if any of the GPaths are invalid
 526
 527			Examples
 528			--------
 529			```python
 530			GPath.join("usr", "local", "bin")          # GPath("usr/local/bin")
 531			GPath.join("/usr/local/bin", "../../bin")  # GPath("/usr/bin")
 532			GPath.join("C:/", "Windows")               # GPath("C:/Windows")
 533			```
 534		"""
 535		flattened_paths: list[GPathLike] = []
 536		for path_or_list in paths:
 537			if _is_gpathlike(path_or_list):
 538				flattened_paths.append(path_or_list)
 539			else:
 540				flattened_paths.extend(path_or_list)
 541
 542		if len(flattened_paths) == 0:
 543			return GPath(encoding=encoding, platform=platform)
 544
 545		combined_path = flattened_paths[0]
 546		if not isinstance(combined_path, GPath):
 547			combined_path = GPath(combined_path, encoding=encoding, platform=platform)
 548		for path in flattened_paths[1:]:
 549			combined_path = combined_path + path
 550
 551		return combined_path
 552
 553
 554	def as_relative(self, parent_level: Optional[int]=None) -> GPath:
 555		"""
 556			Convert the path to a relative path and return a new copy.
 557
 558			Parameters
 559			----------
 560			`​parent_level`
 561			: the number of levels of parent directories that the returned path should be relative to, which may be 0. If set to None, the returned path will have the same parent level as the current path if it is currently a relative path, or have no parent level (i.e. 0) otherwise.
 562
 563			Raises
 564			------
 565			`TypeError` if `​parent_level` is not a valid type
 566
 567			Examples
 568			--------
 569			```python
 570			GPath("/usr/bin").as_relative()      # GPath("usr/bin")
 571			GPath("C:/Windows").as_relative()    # GPath("C:Windows")
 572			GPath("../Documents").as_relative()  # GPath("../Documents")
 573			```
 574		"""
 575
 576		new_path = GPath(self)
 577		new_path._root = False
 578		if parent_level is None:
 579			pass
 580		elif isinstance(parent_level, int):
 581			new_path._parent_level = parent_level
 582		else:
 583			raise TypeError(f"parent_level must be an int: {parent_level} ({type(parent_level)})")
 584
 585		return new_path
 586
 587
 588	def as_absolute(self) -> GPath:
 589		"""
 590			Convert the path to an absolute path and return a new copy.
 591
 592			Any parent directory that the path is relative to will be removed. If the path is already absolute, an identical copy is returned.
 593
 594			Examples
 595			--------
 596			```python
 597			GPath("usr/bin").as_absolute()       # GPath("/usr/bin")
 598			GPath("../Documents").as_absolute()  # GPath("/Documents")
 599			GPath("C:Windows").as_absolute()     # GPath("C:/Windows")
 600			```
 601		"""
 602		new_path = GPath(self)
 603		new_path._root = True
 604		new_path._parent_level = 0
 605		return new_path
 606
 607
 608	def with_drive(self, drive: Union[str, bytes, None]=None) -> GPath:
 609		"""
 610			Return a new copy of the path with the drive set to `​drive`.
 611
 612			If `​drive` is `""` or None, this would be equivalent to `without_drive()`.
 613
 614			Parameters
 615			----------
 616			`​drive`
 617			: the drive for the returned path, or either `""` or None if the returned path should have no drive
 618
 619			Returns
 620			-------
 621			`GPath`
 622			: a new path with the given drive
 623
 624			Raises
 625			------
 626			- `TypeError` if `​drive` is not a valid type
 627			- `ValueError` if `​drive` has more than one character
 628
 629			Examples
 630			--------
 631			```python
 632			GPath("C:/Windows").with_drive()      # GPath("/Windows")
 633			GPath("C:/Windows").with_drive("D")   # GPath("D:/Windows")
 634			GPath("/Windows").with_drive("C")     # GPath("C:/Windows")
 635			```
 636		"""
 637		if drive is None:
 638			drive = ""
 639		elif isinstance(drive, bytes):
 640			if self._encoding is None:
 641				drive = drive.decode(DEFAULT_ENCODING)
 642			else:
 643				drive = drive.decode(self._encoding)
 644		elif isinstance(drive, str):
 645			pass
 646		else:
 647			raise TypeError(f"drive must be a str or bytes object: {drive} ({type(drive)})")
 648
 649		if len(drive) > 1:
 650			raise ValueError(f"drive can only be a single character, an empty string or None: {drive}")
 651
 652		new_path = GPath(self)
 653		new_path._drive = drive
 654		return new_path
 655
 656
 657	def without_drive(self) -> GPath:
 658		"""
 659			Return a new copy of the path without a drive.
 660
 661			Equivalent to `with_drive("")` or `with_drive(None)`.
 662
 663			Returns
 664			-------
 665			`GPath`
 666			: a new path without a drive
 667
 668			Examples
 669			--------
 670			```python
 671			GPath("C:/Windows").without_drive()      # GPath("/Windows")
 672			```
 673		"""
 674		return self.with_drive(None)
 675
 676
 677	def common_with(self, other: GPathLike, allow_current: bool=True, allow_parents: bool=False) -> Optional[GPath]:
 678		"""
 679			Find the longest common base path shared between `self` and `other`, or return None if no such path exists.
 680
 681			A common base path might not exist if one path is an absolute path while the other is a relative path, or if the two paths are in different filesystems (with different drive names), or in other cases as controlled by the `allow_current` and `allow_parents` options.
 682
 683			If using the default options of `allow_current=True` and `allow_parent=False`, the binary operator for bitwise-and can be used: `__and__()` (usage: <code><var>g1</var> & <var>g2</var></code>).
 684
 685			Parameters
 686			----------
 687			`other`
 688			: the path to compare with
 689
 690			`allow_current`
 691			: whether two non-parent relative paths that do not share any components should be considered to have a common base path, namely the imaginary current working directory. For instance, `GPath("some/rel/path").find_common("another/rel/path")` will return `GPath("")` if set to True, or return None if set to False.
 692
 693			`allow_parents`
 694			: whether two relative paths that are relative to different levels of parent directories should be considered to have a common base path, which is the highest level of parent directory between the two paths. For instance, `GPath("../rel/to/parent").find_common("../../rel/to/grandparent")` will return `GPath("../..")` if set to True, or return None if set to False. **Warning**: when set to True, given a higher level of parent directory as output, it may not be possible to find the relative path to one of the inputs (see `relpath_from()`); in most cases False is more appropriate.
 695
 696			Returns
 697			-------
 698			`GPath`
 699			: the longest common base path, which may be empty, if it exists
 700
 701			`None`
 702			: otherwise
 703
 704			Raises
 705			------
 706			`ValueError` if either `self` or `other` is an invalid GPath
 707
 708			Examples
 709			--------
 710			```python
 711			GPath("/usr/bin").find_common("/usr/local/bin")               # GPath("/usr")
 712			GPath("C:/Windows/System32").find_common("C:/Program Files")  # GPath("C:/")
 713			GPath("../Documents").find_common("../Pictures")              # GPath("..")
 714			```
 715		"""
 716		self._validate()
 717		if isinstance(other, GPath):
 718			other._validate()
 719		else:
 720			other = GPath(other, encoding=self._encoding)
 721
 722		if self._drive != other._drive:
 723			return None
 724		if self._root != other._root:
 725			return None
 726
 727		if allow_parents:
 728			allow_current = True
 729
 730		parts = []
 731		if self._root:
 732			common_path = GPath(self)
 733			for part1, part2 in zip(self._parts, other._parts):
 734				if part1 == part2:
 735					parts.append(part1)
 736		else:
 737			if self._parent_level != other._parent_level:
 738				if not allow_parents:
 739					return None
 740
 741				common_path = GPath(self)
 742				common_path._parent_level = max(self._parent_level, other._parent_level)
 743			else:
 744				common_path = GPath(self)
 745				for part1, part2 in zip(self._parts, other._parts):
 746					if part1 == part2:
 747						parts.append(part1)
 748
 749		common_path._parts = tuple(parts)
 750
 751		if not allow_current and not bool(common_path):
 752			if common_path != self or common_path != other:
 753				return None
 754		return common_path
 755
 756
 757	def subpath_from(self, base: GPathLike) -> Optional[GPath]:
 758		"""
 759			Find the relative subpath from `base` to `self` if possible and if `base` contains `self`, or return None otherwise.
 760
 761			None will also be returned if there are unknown components in the subpath from `base` to `self`. For instance, if `self` is relative to the parent directory while `base` is relative to the grandparent directory, the path from the grandparent directory `../..` to the parent directory `..` cannot be known.
 762
 763			Similar to `relpath_from()`, but `self` must be a descendent of `base`.
 764
 765			Parameters
 766			----------
 767			`base`
 768			: the base path that the relative subpath should start from
 769
 770			Returns
 771			-------
 772			`GPath`
 773			: relative subpath from `base` to `self`, which may be empty, if it exists
 774
 775			`None`
 776			: otherwise
 777
 778			Raises
 779			------
 780			`ValueError` if either `self` or `base` is an invalid GPath
 781
 782			Examples
 783			--------
 784			```python
 785			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
 786			GPath("/usr/bin").subpath_from("/usr/local/bin")  # None
 787			GPath("/usr/bin").subpath_from("../Documents")    # None
 788			```
 789		"""
 790		if not isinstance(base, GPath):
 791			base = GPath(base, encoding=self._encoding)
 792
 793		if self.common_with(base, allow_current=True, allow_parents=False) is not None and self in base:
 794			# If self._parent_level > base._parent_level, self is not in base, whereas if self._parent_level < base._parent_level, path from base to self's parent cannot be known
 795			base_length = len(base._parts)
 796			new_path = GPath(self)
 797			new_path._parts = self._parts[base_length:]  # () when self == base
 798			new_path._drive = ""
 799			new_path._root = False
 800			new_path._parent_level = 0
 801			return new_path
 802		else:
 803			return None
 804
 805
 806	def relpath_from(self, origin: GPathLike) -> Optional[GPath]:
 807		"""
 808			Find the relative path from `origin` to `self` if possible, or return None otherwise.
 809
 810			None will also be returned if there are unknown components in the relative path from `origin` to `self`. For instance, if `self` is relative to the parent directory while `base` base is relative to the grandparent directory, the path from the grandparent directory `../..` to the parent directory `..` cannot be known.
 811
 812			Similar to `subpath_from()`, but `self` does not need to be a descendent of `origin`.
 813
 814			Parameters
 815			----------
 816			`origin`
 817			: the origin that the relative path should start from
 818
 819			Returns
 820			-------
 821			`GPath`
 822			: relative path from `origin` to `self`, which may be empty, if it exists
 823
 824			`None`
 825			: otherwise
 826
 827			Raises
 828			------
 829			`ValueError` if either `self` or `origin` is an invalid GPath
 830
 831			Examples
 832			--------
 833			```python
 834			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
 835			GPath("/usr/bin").subpath_from("/usr/local/bin")  # GPath("../../bin")
 836			GPath("/usr/bin").subpath_from("../Documents")    # None
 837			```
 838		"""
 839		self._validate()
 840		if not isinstance(origin, GPath):
 841			origin = GPath(origin, encoding=self._encoding)
 842
 843		if origin._root:
 844			common = self.common_with(origin)
 845			if common is None:
 846				return None
 847
 848			new_path = GPath(self)
 849			new_path._parent_level = len(origin) - len(common)
 850			new_path._parts = self._parts[len(common):]
 851			new_path._drive = ""
 852			new_path._root = False
 853			return new_path
 854
 855		else:
 856			common = self.common_with(origin, allow_current=True, allow_parents=True)
 857			if common is None:
 858				return None
 859			if common._parent_level > self._parent_level:
 860				return None  # Path from common to self's parent cannot be known
 861
 862			# common._dotdot == self._dotdot
 863			# origin._dotdot <= self._dotdot
 864
 865			new_path = GPath(self)
 866			new_path._drive = ""
 867			new_path._root = False
 868			if len(common) == 0:
 869				if origin._parent_level == self._parent_level:
 870					new_path._parent_level = len(origin)
 871				else:
 872					new_path._parent_level = (common._parent_level - origin._parent_level) + len(origin)
 873				new_path._parts = self._parts
 874			else:
 875				new_path._parent_level = len(origin) - len(common)
 876				new_path._parts = self._parts[len(common):]
 877
 878			return new_path
 879
 880
 881	def render(self, platform: Union[str, Platform, None]) -> render.RenderedPath:
 882		"""
 883			Convert the path to a RenderedPath for printing in a specific target operating system.
 884
 885			This will convert, and coerce if necessary, the generalised abstract GPath into a platform-specific path which can then be converted to a printable string using <code>str(<var>renderred_path</var>)</code>. The resulting string will be in the format preferred by the target platform.
 886
 887			If the GPath contains features that the target platform does not support (such as drive name when the target platform is POSIX), and if there are no analogous features in the target platform, they will be dropped in the rendered path.
 888
 889			The rendered path also implements total ordering with binary comparisons, e.g. <code><var>r1</var> < <var>r2</var></code>, making it useful for sorting and collation. This ordering is done with platform-specific semantics, unlike GPath which does not have meaningful order.
 890
 891			Parameters
 892			----------
 893			`platform`
 894			: the target platform where the path is to be used
 895
 896			Returns
 897			-------
 898			`RenderedPath`
 899			: platform-specific path ready for sorting or output
 900
 901			Examples
 902			--------
 903			```python
 904			# Print examples
 905			print(GPath("/usr/bin").render('linux'))      # /usr/bin
 906			print(GPath("/usr/bin").render('windows'))    # \\usr\\bin
 907			print(GPath("C:/Windows").render('linux'))    # /Windows
 908			print(GPath("C:/Windows").render('windows'))  # C:\\Windows
 909
 910			# Ordering examples
 911			GPath("").render('linux') < GPath("abc").render('linux')       # True
 912			GPath("abc").render('linux') < GPath("..").render('linux')     # True
 913			GPath("..").render('linux') < GPath("../..").render('linux')   # True
 914			GPath("../..").render('linux') < GPath("/").render('linux')    # True
 915			GPath("/").render('linux') < GPath("C:/").render('linux')      # False
 916			GPath("/").render('linux') <= GPath("C:/").render('linux')     # True
 917			GPath("/").render('windows') < GPath("C:/").render('windows')  # True
 918			```
 919		"""
 920		if platform is None:
 921			platform = DEFAULT_PLATFORM
 922		elif isinstance(platform, str):
 923			platform = Platform.from_str(platform)
 924		return render.get_type(platform)(self)
 925
 926
 927	def __hash__(self) -> int:
 928		"""
 929			Calculate hash of the GPath object.
 930
 931			Usage: <code>hash(<var>g</var>)</code>
 932		"""
 933		return hash(self._tuple)
 934
 935
 936	def __eq__(self, other: GPathLike) -> bool:  # type: ignore
 937		"""
 938			Check if two GPaths are completely identical.
 939
 940			Always return False if `other` is not a GPath object, even if it is a GPath-like object.
 941
 942			Usage: <code><var>g1</var> == <var>g2</var></code>
 943
 944			Examples
 945			--------
 946			```python
 947			GPath("/usr/bin") == GPath("/usr/bin")  # True
 948			GPath("/usr/bin") == GPath("usr/bin")   # False
 949			GPath("C:/") == GPath("D:/")            # False
 950			```
 951		"""
 952		if not isinstance(other, GPath):
 953			other = GPath(other, encoding=self._encoding)
 954		return self._tuple == other._tuple
 955
 956
 957	def __bool__(self) -> bool:
 958		"""
 959			False if `self` is a relative path without any relative components and without a drive, and True otherwise.
 960
 961			Usage: <code>bool(<var>g</var>)</code>, <code>not <var>g</var></code>, or <code>if <var>g</var>:</code>
 962
 963			Examples
 964			--------
 965			```python
 966			bool(GPath("/"))    # True
 967			bool(GPath(".."))   # True
 968			bool(GPath("doc"))  # True
 969			bool(GPath(""))     # False
 970			```
 971		"""
 972		return self._root or self._drive != "" or self._parent_level != 0 or len(self._parts) > 0
 973
 974
 975	def __str__(self) -> str:
 976		"""
 977			Return a platform-independent string representation of the path.
 978
 979			Usage: <code>str(<var>g</var>)</code>
 980		"""
 981		return str(self.render(Platform.GENERIC))
 982
 983
 984	def __repr__(self) -> str:
 985		"""
 986			Return a string that, when printed, gives the Python code associated with instantiating the GPath object.
 987
 988			Usage: <code>repr(<var>g</var>)</code>
 989		"""
 990		if self._platform is None:
 991			platform_repr = ""
 992		else:
 993			platform_repr = f", platform={repr(self._platform)}"
 994
 995		if self._encoding is None:
 996			encoding_repr = ""
 997		else:
 998			encoding_repr = f", encoding={repr(self._encoding)}"
 999
1000		if bool(self):
1001			return f"GPath({repr(str(self))}{platform_repr}{encoding_repr})"
1002		else:
1003			return f"GPath({repr('')}{platform_repr}{encoding_repr})"
1004
1005
1006	def __len__(self) -> int:
1007		"""
1008			Get the number of named path components, excluding any drive name or parent directories.
1009
1010			Usage: <code>len(<var>g</var>)</code>
1011
1012			Examples
1013			--------
1014			```python
1015			len(GPath("/usr/bin"))    # 2
1016			len(GPath("/"))           # 0
1017			len(GPath("C:/Windows"))  # 0
1018			len(GPath("C:/"))         # 0
1019			```
1020		"""
1021		return len(self._parts)
1022
1023
1024	def __getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:
1025		"""
1026			Get a 0-indexed named path component, or a slice of path components, excluding any drive name or parent directories.
1027
1028			Usage: <code><var>g</var>[<var>n</var>]</code>, <code><var>g</var>[<var>start</var>:<var>end</var>]</code>, <code><var>g</var>[<var>start</var>:<var>end</var>:<var>step</var>]</code>, etc.
1029
1030			Examples
1031			--------
1032			```python
1033			GPath("/usr/local/bin")[1]    # "local"
1034			GPath("/usr/local/bin")[-1]   # "bin"
1035			GPath("/usr/local/bin")[1:]   # ["local", "bin"]
1036			GPath("/usr/local/bin")[::2]  # ["usr", "bin"]
1037			```
1038		"""
1039		if isinstance(index, int):
1040			return self._parts[index]
1041		elif isinstance(index, slice):
1042			return list(self._parts[index])
1043
1044
1045	def __iter__(self) -> Iterator[str]:
1046		"""
1047			Get an iterator through the named path components, excluding any drive name or parent directories.
1048
1049			Usage: <code>iter(<var>g</var>)</code> or <code>for <var>p</var> in <var>g</var>:</code>
1050		"""
1051		return iter(self._parts)
1052
1053
1054	def __contains__(self, other: GPathLike) -> bool:
1055		"""
1056			Check if the path represented by `self` contains the path represented by `other`; i.e. check if `self` is a parent directory of `other`.
1057
1058			Usage: <code><var>other</var> in <var>self</var></code>
1059
1060			Raises `ValueError` if either GPath is invalid
1061
1062			Examples
1063			--------
1064			```python
1065			GPath("/usr/local/bin") in GPath("/usr")  # True
1066			GPath("/usr/local/bin") in GPath("/bin")  # False
1067			GPath("..") in GPath("../..")             # True
1068			GPath("..") in GPath("C:/")               # False
1069			```
1070		"""
1071		if not isinstance(other, GPath):
1072			other = GPath(other, encoding=self._encoding)
1073
1074		common_path = self.common_with(other, allow_current=True, allow_parents=True)
1075		return common_path is not None and common_path == self
1076
1077
1078	def __add__(self, other: GPathLike) -> GPath:
1079		"""
1080			Add (concatenate) `other` to the end of `self`, and return a new copy.
1081
1082			If `other` is an absolute path, the returned path will be an absolute path that matches `other`, apart from the drive name.
1083
1084			If `other` has a drive, the returned path will have the same drive as `other`. Otherwise, the returned path will have the same drive as `self`. If neither has a drive, the returned path will not have a drive as well.
1085
1086			Alias: `__truediv__()`
1087
1088			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1089
1090			Raises `ValueError` if either GPath is invalid
1091
1092			Examples
1093			--------
1094			```python
1095			GPath("/usr") + GPath("local/bin")                   # GPath("/usr/local/bin")
1096			GPath("C:/Windows/System32") + GPath("../SysWOW64")  # GPath("C:/Windows/SysWOW64")
1097			GPath("C:/Windows/System32") + GPath("/usr/bin")     # GPath("C:/usr/bin")
1098			GPath("..") + GPath("../..")                         # GPath("../../..")
1099			GPath("..") / GPath("../..")                         # GPath("../../..")
1100			```
1101		"""
1102		if isinstance(other, GPath):
1103			other._validate
1104		else:
1105			other = GPath(other, encoding=self._encoding)
1106
1107		new_path = GPath(self)
1108		if other._root:
1109			new_path._parts = other._parts
1110			new_path._root = other._root
1111			new_path._parent_level = other._parent_level
1112		else:
1113			new_parts = [part for part in self._parts]
1114			for i in range(other._parent_level):
1115				if len(new_parts) > 0:
1116					new_parts.pop()
1117				elif not new_path._root:
1118					new_path._parent_level += 1
1119				else:
1120					pass  # parent of directory of root is still root
1121
1122			new_parts.extend(other._parts)
1123			new_path._parts = tuple(new_parts)
1124
1125		if other._drive != "":
1126			new_path._drive = other._drive
1127
1128		return new_path
1129
1130
1131	def __sub__(self, n: int) -> GPath:
1132		"""
1133			Remove `n` components from the end of the path and return a new copy.
1134
1135			Usage: <code><var>self</var> - <var>n</var></code>
1136
1137			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative
1138
1139			Examples
1140			--------
1141			```python
1142			GPath("C:/Windows/System32") - 1  # GPath("C:/Windows")
1143			GPath("/usr/bin") - 2             # GPath("/")
1144			GPath("Documents") - 3            # GPath("..")
1145			GPath("/") - 1                    # GPath("/")
1146			```
1147		"""
1148		if n < 0:
1149			raise ValueError("cannot subtract a negative number of components from the path: {n}; use __add__() instead")
1150
1151		new_path = GPath(self)
1152		new_parts = [part for part in self._parts]
1153		for i in range(n):
1154			if len(new_parts) > 0:
1155				new_parts.pop()
1156			elif not new_path._root:
1157				new_path._parent_level += 1
1158			else:
1159				pass  # removing components from root should still give root
1160		new_path._parts = tuple(new_parts)
1161		return new_path
1162
1163
1164	def __mul__(self, n: int) -> GPath:
1165		"""
1166			Duplicate the named components of `self` `n` times and return a new path with the duplicated components.
1167
1168			Named components will be duplicated separately from the components representing a parent directory. If `self` is an absolute path, only the relative components will be duplicated.
1169
1170			If `n` is 0, the result is an empty path (either relative or absolute).
1171
1172			Usage: <code><var>self</var> * <var>n</var></code>
1173
1174			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative.
1175
1176			Examples
1177			--------
1178			```python
1179			GPath("/usr/bin") * 2    # GPath("/usr/bin/usr/bin")
1180			GPath("../docs") * 2     # GPath("../../docs/docs")
1181			GPath("C:/Windows") * 0  # GPath("C:/")
1182			```
1183		"""
1184		if n < 0:
1185			raise ValueError("cannot multiply path by a negative integer: {n}")
1186		new_path = GPath(self)
1187		new_path._parent_level = self._parent_level * n
1188		new_path._parts = self._parts * n
1189		return new_path
1190
1191
1192	def __truediv__(self, other: GPathLike) -> GPath:
1193		"""
1194			Alias of `__add__()`.
1195
1196			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1197		"""
1198		return self.__add__(other)
1199
1200
1201	def __and__(self, other: GPathLike) -> Union[GPath, None]:
1202		"""
1203			Equivalent to `self.common_with(other)`, using the default options of `common_with()`.
1204
1205			Usage: <code><var>g1</var> & <var>g2</var></code>
1206		"""
1207		return self.common_with(other)
1208
1209
1210	def __lshift__(self, n: int) -> GPath:
1211		"""
1212			Move the imaginary current working directory `n` steps up the filesystem tree.
1213
1214			If `self` is a relative path, remove up to `n` levels of parent directories from the start of the path and return a copy. If it is an absolute path, return a copy of `self` unchanged.
1215
1216			If `n` is negative, this is equivalent to `__rshift__(-n)`.
1217
1218			Usage: <code><var>self</var> << <var>n</var></code>
1219
1220			Raises `ValueError` if `self` is an invalid GPath.
1221
1222			Examples
1223			--------
1224			```python
1225			GPath("../SysWOW64/drivers") << 1  # GPath("SysWOW64/drivers")
1226			GPath("../doc") << 2               # GPath("doc")
1227			GPath("/usr/bin") << 2             # GPath("/usr/bin")
1228			```
1229		"""
1230		if n < 0:
1231			return self.__rshift__(-1 * n)
1232		new_path = GPath(self)
1233		if not new_path._root:
1234			new_path._parent_level = max(new_path._parent_level - n, 0)
1235		return new_path
1236
1237
1238	def __rshift__(self, n: int) -> GPath:
1239		"""
1240			Move the imaginary current working directory `n` steps down the filesystem tree.
1241
1242			If `self` is a relative path, add `n` levels of parent directories to the start of the path and return a copy. If it is an absolute path, return a copy of `self` unchanged.
1243
1244			If `n` is negative, this is equivalent to `__lshift__(-n)`.
1245
1246			Usage: <code><var>self</var> >> <var>n</var></code>
1247
1248			Raises `ValueError` if `self` is an invalid GPath
1249
1250			Examples
1251			--------
1252			```python
1253			GPath("../SysWOW64/drivers") >> 1  # GPath("../../SysWOW64/drivers")
1254			GPath("/usr/bin") >> 2             # GPath("/usr/bin")
1255			```
1256		"""
1257		if n < 0:
1258			return self.__lshift__(-1 * n)
1259		new_path = GPath(self)
1260		if not new_path._root:
1261			new_path._parent_level += n
1262		return new_path
1263
1264
1265	@property
1266	def _tuple(self) -> tuple:
1267		# Get a tuple of all fields
1268		return (
1269			self._root,
1270			self._drive,
1271			self._parent_level,
1272			self._parts,
1273			self._platform,
1274			self._encoding,
1275		)
1276
1277
1278	def _validate(self) -> bool:
1279		# Check if self is in a valid state
1280		if self._parent_level < 0:
1281			raise ValueError(f"invalid GPath, _parent cannot be negative: {repr(self)}")
1282		if self._root:
1283			if self._parent_level != 0:
1284				raise ValueError(f"invalid GPath, _parent must be 0 when root is True: {repr(self)}")
1285		return True

An immutable generalised abstract file path that has no dependency on any real filesystem.

The path can be manipulated on a system that is different from where it originated, notably including systems with a different operating system, and it can represent file paths on a system other than local. Examples where this is useful include remote management of servers and when cross-compiling source code for a different platform.

Since GPath objects are immutable, all operations return a new instance. The path is always stored in a normalised state, and is always treated as case sensitive.

The path can be rendered as a string using str(g), which will use / as the path separator if possible to maximise cross-platform compatibility.

GPath( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', platform: Union[str, platform.Platform, NoneType] = None, encoding: Optional[str] = None)
102	def __init__(self,
103		path: Union[str, bytes, os.PathLike, GPath, None]="",
104		platform: Optional[Union[str, Platform]]=None,
105		encoding: Optional[str]=None,
106	):
107		"""
108			Initialise a normalised and generalised abstract file path, possibly by copying an existing GPath object.
109
110			Parameters
111			----------
112			`path`
113			: path-like object representing a (possibly unnormalised) file path, or a GPath object to be copied
114
115			`platform`
116			: interpret `path` as originating from a specific platform. This is usually not required for normal file paths on Windows, Linux or macOS, and is needed only for edge cases (see [compatibility](https://github.com/yushiyangk/gpath#compatibility) in the readme). If `path` is a GPath, this argument has no effect. The platform name should be one of the keys in `gpath.platform.platform_names`. If specified, the platform will propagate to new GPaths returned by operations on this GPath; for binary operations on two GPaths, the platform specified by the left operand will be propagated. See also the static methods `from_*()`.
117
118			`encoding`
119			: the text encoding that should be used to decode paths given as bytes-like objects; if not specified, `'utf_8'` will be used by default. The encoding name should be one of the standard Python text encodings, as listed in the `codecs` module of the standard library. If specified, the encoding will propagate to new GPaths returned by operations on this GPath; for binary operations on two GPaths, the encoding specified by the left operand will be propagated.
120
121			Raises
122			------
123			`ValueError` if `path` is an invalid GPath
124
125			Examples
126			--------
127			```python
128			GPath("/")
129			GPath("/usr/bin")
130			GPath("C:/Program Files")
131			```
132		"""
133
134		self._parts: tuple[str, ...] = tuple()  # root- or parent- relative path
135		self._root: bool = False
136		self._drive: str = ""
137		self._parent_level: int = 0
138
139		self._platform: Union[Platform, None] = Platform.from_str(platform) if isinstance(platform, str) else platform
140		self._encoding: Union[str, None] = encoding
141
142		if isinstance(path, GPath):
143			path._validate()
144			self._parts = path._parts
145			self._root = path._root
146			self._drive = path._drive
147			self._parent_level = path._parent_level
148
149			self._platform = path._platform if self._platform is None else self._platform
150			self._encoding = path._encoding if self._encoding is None else self._encoding
151			return
152
153		if path is None or path == "":
154			return
155
156		path = os.fspath(path)
157
158		if isinstance(path, bytes):
159			if self._encoding is None:
160				path = path.decode(DEFAULT_ENCODING)
161			else:
162				path = path.decode(self._encoding)
163
164		path = cast(str, path)
165
166		if self._platform is None:
167			platform = Platform.GENERIC
168		else:
169			platform = self._platform
170
171		if platform == Platform.POSIX:
172			for root in _rules.posix_rules.roots:
173				if path.startswith(root):
174					self._root = True
175					break
176
177			if self._root:
178				rootless_path = path[1:]
179			else:
180				rootless_path = path
181
182			parts = _split_relative(rootless_path, delimiters=_rules.posix_rules.separators)
183
184		elif platform == Platform.WINDOWS:
185			if len(path) >= 2 and path[1] in _rules.windows_rules.drive_postfixes:
186				self._drive = path[0]
187				driveless_path = path[2:]
188			else:
189				driveless_path = path
190
191			for root in _rules.windows_rules.roots:
192				if driveless_path.startswith(root):
193					self._root = True
194					break
195
196			if self._root:
197				rootless_path = driveless_path[1:]
198			else:
199				rootless_path = driveless_path
200
201			parts = _split_relative(rootless_path, delimiters=_rules.windows_rules.separators)
202
203		else:
204			if len(path) >= 2 and path[1] in _rules.generic_rules.drive_postfixes:
205				self._drive = path[0]
206				driveless_path = path[2:]
207			else:
208				driveless_path = path
209
210			for root in _rules.generic_rules.roots:
211				if driveless_path.startswith(root):
212					self._root = True
213					break
214
215			if self._root:
216				rootless_path = driveless_path[1:]
217			else:
218				rootless_path = driveless_path
219
220			parts = _split_relative(rootless_path, delimiters=_rules.generic_rules.separators)
221
222
223		parts = _normalise_relative(parts)
224		parent_level = 0
225		while parent_level < len(parts) and parts[parent_level] in _rules.generic_rules.parent_indicators:
226			parent_level += 1
227		self._parts = tuple(parts[parent_level:])
228		if self._root == False:
229			self._parent_level = parent_level

Initialise a normalised and generalised abstract file path, possibly by copying an existing GPath object.

Parameters

path : path-like object representing a (possibly unnormalised) file path, or a GPath object to be copied

platform : interpret path as originating from a specific platform. This is usually not required for normal file paths on Windows, Linux or macOS, and is needed only for edge cases (see compatibility in the readme). If path is a GPath, this argument has no effect. The platform name should be one of the keys in gpath.platform.platform_names. If specified, the platform will propagate to new GPaths returned by operations on this GPath; for binary operations on two GPaths, the platform specified by the left operand will be propagated. See also the static methods from_*().

encoding : the text encoding that should be used to decode paths given as bytes-like objects; if not specified, 'utf_8' will be used by default. The encoding name should be one of the standard Python text encodings, as listed in the codecs module of the standard library. If specified, the encoding will propagate to new GPaths returned by operations on this GPath; for binary operations on two GPaths, the encoding specified by the left operand will be propagated.

Raises

ValueError if path is an invalid GPath

Examples

GPath("/")
GPath("/usr/bin")
GPath("C:/Program Files")
named_parts: list[str]

Read-only named components of the path, not including the filesystem root, drive name, or any parent directories

Examples

GPath("usr/local/bin").named_parts     # ["usr", "local", "bin"]
GPath("../../Documents").named_parts   # ["Documents"]
GPath("/usr/bin").named_parts          # ["usr", "bin"]
GPath("C:/Program Files").named_parts  # ["Program Files"]
relative_parts: list[str]

Read-only relative components of the path, not including the filesystem root or drive name, including one item for each level of parent directory

Examples

GPath("usr/local/bin").relative_parts     # ["usr", "local", "bin"]
GPath("../../Documents").relative_parts   # ["..", "..", "Documents"]
GPath("/usr/bin").relative_parts          # ["usr", "bin"]
GPath("C:/Program Files").relative_parts  # ["Program Files"]
absolute: bool

Read-only flag for whether the path is an absolute path

Examples

GPath("/").absolute                # True
GPath("C:/Windows").absolute       # True
GPath("local/bin").absolute        # False
GPath("../../Documents").absolute  # False
root: bool

Read-only flag for whether the path is exactly the root of the filesystem

Examples

GPath("/").root                # True
GPath("C:/").root              # True
GPath("/usr/bin").root         # False
GPath("C:/Windows").root       # False
GPath("../../Documents").root  # False
drive: str

Read-only drive name

Examples

GPath("C:/Windows").drive       # "C:"
GPath("/usr/bin").drive         # ""
GPath("../../Documents").drive  # ""
parent_level: int

Read-only number of levels of parent directories that the path is relative to, which may be 0

Examples

GPath("../../Documents").parent_level  # 2
GPath("usr/local/bin").parent_level    # 0
parent_parts: list[str]

Read-only path components representing a parent directory that it is relative to, if any, with one item for each level of parent directory

Examples

GPath("../../Documents").parent_parts  # ["..", ".."]
GPath("usr/local/bin").parent_parts    # []
encoding: Optional[str]

Read-only encoding used to decode other paths that are given as bytes-like objects, or None if the default should be used

platform: Optional[str]

Read-only platform that other non-GPath operands should be interepreted as, or None if the default should be used

@staticmethod
def from_posix( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', encoding: Optional[str] = None) -> GPath:
355	@staticmethod
356	def from_posix(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
357		"""
358			Initialise a GPath that originates from a POSIX-like operating system, or copy a GPath such that any future non-GPath operands would be interpreted as originating from a POSIX-like operating system.
359
360			See `__init__()` for details.
361
362			Equivalent to `GPath(path, platform='posix')`
363			```
364		"""
365		return GPath(path, platform=Platform.POSIX, encoding=encoding)

Initialise a GPath that originates from a POSIX-like operating system, or copy a GPath such that any future non-GPath operands would be interpreted as originating from a POSIX-like operating system.

See __init__() for details.

Equivalent to GPath(path, platform='posix') ```

@staticmethod
def from_linux( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', encoding: Optional[str] = None) -> GPath:
367	@staticmethod
368	def from_linux(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
369		"""
370			Alias of `from_posix()`
371		"""
372		return GPath.from_posix(path, encoding=encoding)

Alias of from_posix()

@staticmethod
def from_macos( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', encoding: Optional[str] = None) -> GPath:
374	@staticmethod
375	def from_macos(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
376		"""
377			Alias of `from_posix()`
378		"""
379		return GPath.from_posix(path, encoding=encoding)

Alias of from_posix()

@staticmethod
def from_windows( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', encoding: Optional[str] = None) -> GPath:
382	@staticmethod
383	def from_windows(path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None) -> GPath:
384		"""
385			Initialise a GPath that originates from a Windows operating system, or copy a GPath such that any future non-GPath operands would be interpreted as originating from a Windows operating system.
386
387			See `__init__()` for details.
388
389			Equivalent to `GPath(path, platform='windows')`
390			```
391		"""
392		return GPath(path, platform=Platform.WINDOWS, encoding=encoding)

Initialise a GPath that originates from a Windows operating system, or copy a GPath such that any future non-GPath operands would be interpreted as originating from a Windows operating system.

See __init__() for details.

Equivalent to GPath(path, platform='windows') ```

@staticmethod
def partition( *paths, allow_current: bool = True, allow_parents: bool = True, platform: Union[str, platform.Platform, NoneType] = None, encoding: Optional[str] = None) -> dict[GPath, list[GPath]]:
403	@staticmethod
404	def partition(
405		*paths,
406		allow_current: bool=True,
407		allow_parents: bool=True,
408		platform: Optional[Union[str, Platform]]=None,
409		encoding: Optional[str]=None,
410	) -> dict[GPath, list[GPath]]:
411		"""
412			Partition a collection of paths based on shared common base paths such that each path belongs to one partition.
413
414			For each partition, return a list of relative paths from the base path of that partition to each corresponding input path within that partition, unless `allow_parents` is True (see below). If the input collection is ordered, the output order is preserved within each partition. If the input collection contains duplicates, the corresponding output lists will as well.
415
416			The number of partitions is minimised by merging partitions as much as possible, so that each partition represents the highest possible level base path. Two partitions can no longer be merged when there is no common base path between them, as determined by `common_with()`. This method takes the same optional arguments as `common_with()`, with the same default values.
417
418			Parameters
419			----------
420			`paths: Iterable[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
421			: the paths to be partitioned, which can be given as either a list-like object or as variadic arguments
422
423			`allow_current`
424			: whether non-parent relative paths with no shared components should be considered to have a common base path (see `common_with()`)
425
426			`allow_parents`
427			: whether paths that are relative to different levels of parent directories should be considered to have a common base path (see `common_with()`). **Warning**: when set to True, the output lists for each partition are invalidated, and explicitly set to empty. This is because it is not possible in general to obtain a relative path from the base path to its members if the base path is a parent directory of a higher level than the member (see `relpath_from()`). This  option should be True if and only if the list of members in each partition are not of interest; in most cases False is more appropriate.
428
429			`​platform`
430			: the originating platform that should be assumed when interpreting non-GPath objects in `paths`, if any (see `__init__()`).
431
432			`​encoding`
433			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
434
435			Returns
436			-------
437			a dictionary that maps the common base path of each partition to a list of relative paths
438
439			Raises
440			------
441			  `ValueError`
442			  if any of the GPaths are invalid
443
444			Examples
445			--------
446			```python
447			partitions = GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")
448
449			assert partitions == {
450				GPath("/usr")      : [GPath("bin"), GPath("local")],
451				GPath("../../doc") : [GPath("")],
452				GPath("C:/")       : [GPath("Windows"), GPath("Program Files")],
453			}
454			```
455		"""
456		flattened_paths: list[GPathLike] = []
457		for path_or_list in paths:
458			if _is_gpathlike(path_or_list):
459				flattened_paths.append(path_or_list)
460			else:
461				flattened_paths.extend(path_or_list)
462		gpaths = [path if isinstance(path, GPath) else GPath(path, encoding=encoding, platform=platform) for path in flattened_paths]
463
464		partition_map = {}
465		if len(gpaths) > 0:
466			if allow_parents == True:
467				partition_map[gpaths[0]] = []
468			else:
469				partition_map[gpaths[0]] = [gpaths[0]]
470
471		for path in gpaths[1:]:
472			partition_found = False
473			for partition in partition_map:
474				candidate_common = partition.common_with(path, allow_current=allow_current, allow_parents=allow_parents)
475				if candidate_common is not None:
476					partition_found = True
477					if candidate_common != partition:
478						partition_map[candidate_common] = partition_map[partition]
479						del partition_map[partition]
480					if allow_parents == False:
481						partition_map[candidate_common].append(path)
482					break
483			if not partition_found:
484				if allow_parents == True:
485					partition_map[path] = []
486				else:
487					partition_map[path] = [path]
488
489		for partition, path_list in partition_map.items():
490			partition_map[partition] = [path.subpath_from(partition) for path in path_list]
491
492		return partition_map

Partition a collection of paths based on shared common base paths such that each path belongs to one partition.

For each partition, return a list of relative paths from the base path of that partition to each corresponding input path within that partition, unless allow_parents is True (see below). If the input collection is ordered, the output order is preserved within each partition. If the input collection contains duplicates, the corresponding output lists will as well.

The number of partitions is minimised by merging partitions as much as possible, so that each partition represents the highest possible level base path. Two partitions can no longer be merged when there is no common base path between them, as determined by common_with(). This method takes the same optional arguments as common_with(), with the same default values.

Parameters

paths: Iterable[GPath | str | bytes | os.PathLike] or *paths: GPath | str | bytes | os.PathLike : the paths to be partitioned, which can be given as either a list-like object or as variadic arguments

allow_current : whether non-parent relative paths with no shared components should be considered to have a common base path (see common_with())

allow_parents : whether paths that are relative to different levels of parent directories should be considered to have a common base path (see common_with()). Warning: when set to True, the output lists for each partition are invalidated, and explicitly set to empty. This is because it is not possible in general to obtain a relative path from the base path to its members if the base path is a parent directory of a higher level than the member (see relpath_from()). This option should be True if and only if the list of members in each partition are not of interest; in most cases False is more appropriate.

​platform : the originating platform that should be assumed when interpreting non-GPath objects in paths, if any (see __init__()).

​encoding : the text encoding that should be used to decode bytes-like objects in paths, if any (see __init__()).

Returns

a dictionary that maps the common base path of each partition to a list of relative paths

Raises

ValueError if any of the GPaths are invalid

Examples

partitions = GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")

assert partitions == {
	GPath("/usr")      : [GPath("bin"), GPath("local")],
	GPath("../../doc") : [GPath("")],
	GPath("C:/")       : [GPath("Windows"), GPath("Program Files")],
}
@staticmethod
def join( *paths, platform: Union[str, platform.Platform, NoneType] = None, encoding: Optional[str] = None) -> GPath:
503	@staticmethod
504	def join(*paths, platform: Optional[Union[str, Platform]]=None, encoding: Optional[str]=None) -> GPath:
505		"""
506			Join a sequence of paths into a single path. Apart from the first item in the sequence, all subsequent paths should be relative paths and any absolute paths will be ignored.
507
508			Parameters
509			----------
510			`paths`: `Sequence[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
511			: the paths to be combined, which can be given as either a list-like object or as variadic arguments
512
513			`​platform`
514			: the originating platform that should be assumed when interpreting non-GPath objects in `paths`, if any (see `__init__()`).
515
516			`​encoding`
517			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
518
519			Returns
520			-------
521			the combined path
522
523			Raises
524			------
525			`ValueError` if any of the GPaths are invalid
526
527			Examples
528			--------
529			```python
530			GPath.join("usr", "local", "bin")          # GPath("usr/local/bin")
531			GPath.join("/usr/local/bin", "../../bin")  # GPath("/usr/bin")
532			GPath.join("C:/", "Windows")               # GPath("C:/Windows")
533			```
534		"""
535		flattened_paths: list[GPathLike] = []
536		for path_or_list in paths:
537			if _is_gpathlike(path_or_list):
538				flattened_paths.append(path_or_list)
539			else:
540				flattened_paths.extend(path_or_list)
541
542		if len(flattened_paths) == 0:
543			return GPath(encoding=encoding, platform=platform)
544
545		combined_path = flattened_paths[0]
546		if not isinstance(combined_path, GPath):
547			combined_path = GPath(combined_path, encoding=encoding, platform=platform)
548		for path in flattened_paths[1:]:
549			combined_path = combined_path + path
550
551		return combined_path

Join a sequence of paths into a single path. Apart from the first item in the sequence, all subsequent paths should be relative paths and any absolute paths will be ignored.

Parameters

paths: Sequence[GPath | str | bytes | os.PathLike] or *paths: GPath | str | bytes | os.PathLike : the paths to be combined, which can be given as either a list-like object or as variadic arguments

​platform : the originating platform that should be assumed when interpreting non-GPath objects in paths, if any (see __init__()).

​encoding : the text encoding that should be used to decode bytes-like objects in paths, if any (see __init__()).

Returns

the combined path

Raises

ValueError if any of the GPaths are invalid

Examples

GPath.join("usr", "local", "bin")          # GPath("usr/local/bin")
GPath.join("/usr/local/bin", "../../bin")  # GPath("/usr/bin")
GPath.join("C:/", "Windows")               # GPath("C:/Windows")
def as_relative(self, parent_level: Optional[int] = None) -> GPath:
554	def as_relative(self, parent_level: Optional[int]=None) -> GPath:
555		"""
556			Convert the path to a relative path and return a new copy.
557
558			Parameters
559			----------
560			`​parent_level`
561			: the number of levels of parent directories that the returned path should be relative to, which may be 0. If set to None, the returned path will have the same parent level as the current path if it is currently a relative path, or have no parent level (i.e. 0) otherwise.
562
563			Raises
564			------
565			`TypeError` if `​parent_level` is not a valid type
566
567			Examples
568			--------
569			```python
570			GPath("/usr/bin").as_relative()      # GPath("usr/bin")
571			GPath("C:/Windows").as_relative()    # GPath("C:Windows")
572			GPath("../Documents").as_relative()  # GPath("../Documents")
573			```
574		"""
575
576		new_path = GPath(self)
577		new_path._root = False
578		if parent_level is None:
579			pass
580		elif isinstance(parent_level, int):
581			new_path._parent_level = parent_level
582		else:
583			raise TypeError(f"parent_level must be an int: {parent_level} ({type(parent_level)})")
584
585		return new_path

Convert the path to a relative path and return a new copy.

Parameters

​parent_level : the number of levels of parent directories that the returned path should be relative to, which may be 0. If set to None, the returned path will have the same parent level as the current path if it is currently a relative path, or have no parent level (i.e. 0) otherwise.

Raises

TypeError if ​parent_level is not a valid type

Examples

GPath("/usr/bin").as_relative()      # GPath("usr/bin")
GPath("C:/Windows").as_relative()    # GPath("C:Windows")
GPath("../Documents").as_relative()  # GPath("../Documents")
def as_absolute(self) -> GPath:
588	def as_absolute(self) -> GPath:
589		"""
590			Convert the path to an absolute path and return a new copy.
591
592			Any parent directory that the path is relative to will be removed. If the path is already absolute, an identical copy is returned.
593
594			Examples
595			--------
596			```python
597			GPath("usr/bin").as_absolute()       # GPath("/usr/bin")
598			GPath("../Documents").as_absolute()  # GPath("/Documents")
599			GPath("C:Windows").as_absolute()     # GPath("C:/Windows")
600			```
601		"""
602		new_path = GPath(self)
603		new_path._root = True
604		new_path._parent_level = 0
605		return new_path

Convert the path to an absolute path and return a new copy.

Any parent directory that the path is relative to will be removed. If the path is already absolute, an identical copy is returned.

Examples

GPath("usr/bin").as_absolute()       # GPath("/usr/bin")
GPath("../Documents").as_absolute()  # GPath("/Documents")
GPath("C:Windows").as_absolute()     # GPath("C:/Windows")
def with_drive(self, drive: Union[str, bytes, NoneType] = None) -> GPath:
608	def with_drive(self, drive: Union[str, bytes, None]=None) -> GPath:
609		"""
610			Return a new copy of the path with the drive set to `​drive`.
611
612			If `​drive` is `""` or None, this would be equivalent to `without_drive()`.
613
614			Parameters
615			----------
616			`​drive`
617			: the drive for the returned path, or either `""` or None if the returned path should have no drive
618
619			Returns
620			-------
621			`GPath`
622			: a new path with the given drive
623
624			Raises
625			------
626			- `TypeError` if `​drive` is not a valid type
627			- `ValueError` if `​drive` has more than one character
628
629			Examples
630			--------
631			```python
632			GPath("C:/Windows").with_drive()      # GPath("/Windows")
633			GPath("C:/Windows").with_drive("D")   # GPath("D:/Windows")
634			GPath("/Windows").with_drive("C")     # GPath("C:/Windows")
635			```
636		"""
637		if drive is None:
638			drive = ""
639		elif isinstance(drive, bytes):
640			if self._encoding is None:
641				drive = drive.decode(DEFAULT_ENCODING)
642			else:
643				drive = drive.decode(self._encoding)
644		elif isinstance(drive, str):
645			pass
646		else:
647			raise TypeError(f"drive must be a str or bytes object: {drive} ({type(drive)})")
648
649		if len(drive) > 1:
650			raise ValueError(f"drive can only be a single character, an empty string or None: {drive}")
651
652		new_path = GPath(self)
653		new_path._drive = drive
654		return new_path

Return a new copy of the path with the drive set to ​drive.

If ​drive is "" or None, this would be equivalent to without_drive().

Parameters

​drive : the drive for the returned path, or either "" or None if the returned path should have no drive

Returns

GPath : a new path with the given drive

Raises

  • TypeError if ​drive is not a valid type
  • ValueError if ​drive has more than one character

Examples

GPath("C:/Windows").with_drive()      # GPath("/Windows")
GPath("C:/Windows").with_drive("D")   # GPath("D:/Windows")
GPath("/Windows").with_drive("C")     # GPath("C:/Windows")
def without_drive(self) -> GPath:
657	def without_drive(self) -> GPath:
658		"""
659			Return a new copy of the path without a drive.
660
661			Equivalent to `with_drive("")` or `with_drive(None)`.
662
663			Returns
664			-------
665			`GPath`
666			: a new path without a drive
667
668			Examples
669			--------
670			```python
671			GPath("C:/Windows").without_drive()      # GPath("/Windows")
672			```
673		"""
674		return self.with_drive(None)

Return a new copy of the path without a drive.

Equivalent to with_drive("") or with_drive(None).

Returns

GPath : a new path without a drive

Examples

GPath("C:/Windows").without_drive()      # GPath("/Windows")
def common_with( self, other: Union[GPath, str, bytes, os.PathLike], allow_current: bool = True, allow_parents: bool = False) -> Optional[GPath]:
677	def common_with(self, other: GPathLike, allow_current: bool=True, allow_parents: bool=False) -> Optional[GPath]:
678		"""
679			Find the longest common base path shared between `self` and `other`, or return None if no such path exists.
680
681			A common base path might not exist if one path is an absolute path while the other is a relative path, or if the two paths are in different filesystems (with different drive names), or in other cases as controlled by the `allow_current` and `allow_parents` options.
682
683			If using the default options of `allow_current=True` and `allow_parent=False`, the binary operator for bitwise-and can be used: `__and__()` (usage: <code><var>g1</var> & <var>g2</var></code>).
684
685			Parameters
686			----------
687			`other`
688			: the path to compare with
689
690			`allow_current`
691			: whether two non-parent relative paths that do not share any components should be considered to have a common base path, namely the imaginary current working directory. For instance, `GPath("some/rel/path").find_common("another/rel/path")` will return `GPath("")` if set to True, or return None if set to False.
692
693			`allow_parents`
694			: whether two relative paths that are relative to different levels of parent directories should be considered to have a common base path, which is the highest level of parent directory between the two paths. For instance, `GPath("../rel/to/parent").find_common("../../rel/to/grandparent")` will return `GPath("../..")` if set to True, or return None if set to False. **Warning**: when set to True, given a higher level of parent directory as output, it may not be possible to find the relative path to one of the inputs (see `relpath_from()`); in most cases False is more appropriate.
695
696			Returns
697			-------
698			`GPath`
699			: the longest common base path, which may be empty, if it exists
700
701			`None`
702			: otherwise
703
704			Raises
705			------
706			`ValueError` if either `self` or `other` is an invalid GPath
707
708			Examples
709			--------
710			```python
711			GPath("/usr/bin").find_common("/usr/local/bin")               # GPath("/usr")
712			GPath("C:/Windows/System32").find_common("C:/Program Files")  # GPath("C:/")
713			GPath("../Documents").find_common("../Pictures")              # GPath("..")
714			```
715		"""
716		self._validate()
717		if isinstance(other, GPath):
718			other._validate()
719		else:
720			other = GPath(other, encoding=self._encoding)
721
722		if self._drive != other._drive:
723			return None
724		if self._root != other._root:
725			return None
726
727		if allow_parents:
728			allow_current = True
729
730		parts = []
731		if self._root:
732			common_path = GPath(self)
733			for part1, part2 in zip(self._parts, other._parts):
734				if part1 == part2:
735					parts.append(part1)
736		else:
737			if self._parent_level != other._parent_level:
738				if not allow_parents:
739					return None
740
741				common_path = GPath(self)
742				common_path._parent_level = max(self._parent_level, other._parent_level)
743			else:
744				common_path = GPath(self)
745				for part1, part2 in zip(self._parts, other._parts):
746					if part1 == part2:
747						parts.append(part1)
748
749		common_path._parts = tuple(parts)
750
751		if not allow_current and not bool(common_path):
752			if common_path != self or common_path != other:
753				return None
754		return common_path

Find the longest common base path shared between self and other, or return None if no such path exists.

A common base path might not exist if one path is an absolute path while the other is a relative path, or if the two paths are in different filesystems (with different drive names), or in other cases as controlled by the allow_current and allow_parents options.

If using the default options of allow_current=True and allow_parent=False, the binary operator for bitwise-and can be used: __and__() (usage: g1 & g2).

Parameters

other : the path to compare with

allow_current : whether two non-parent relative paths that do not share any components should be considered to have a common base path, namely the imaginary current working directory. For instance, GPath("some/rel/path").find_common("another/rel/path") will return GPath("") if set to True, or return None if set to False.

allow_parents : whether two relative paths that are relative to different levels of parent directories should be considered to have a common base path, which is the highest level of parent directory between the two paths. For instance, GPath("../rel/to/parent").find_common("../../rel/to/grandparent") will return GPath("../..") if set to True, or return None if set to False. Warning: when set to True, given a higher level of parent directory as output, it may not be possible to find the relative path to one of the inputs (see relpath_from()); in most cases False is more appropriate.

Returns

GPath : the longest common base path, which may be empty, if it exists

None : otherwise

Raises

ValueError if either self or other is an invalid GPath

Examples

GPath("/usr/bin").find_common("/usr/local/bin")               # GPath("/usr")
GPath("C:/Windows/System32").find_common("C:/Program Files")  # GPath("C:/")
GPath("../Documents").find_common("../Pictures")              # GPath("..")
def subpath_from( self, base: Union[GPath, str, bytes, os.PathLike]) -> Optional[GPath]:
757	def subpath_from(self, base: GPathLike) -> Optional[GPath]:
758		"""
759			Find the relative subpath from `base` to `self` if possible and if `base` contains `self`, or return None otherwise.
760
761			None will also be returned if there are unknown components in the subpath from `base` to `self`. For instance, if `self` is relative to the parent directory while `base` is relative to the grandparent directory, the path from the grandparent directory `../..` to the parent directory `..` cannot be known.
762
763			Similar to `relpath_from()`, but `self` must be a descendent of `base`.
764
765			Parameters
766			----------
767			`base`
768			: the base path that the relative subpath should start from
769
770			Returns
771			-------
772			`GPath`
773			: relative subpath from `base` to `self`, which may be empty, if it exists
774
775			`None`
776			: otherwise
777
778			Raises
779			------
780			`ValueError` if either `self` or `base` is an invalid GPath
781
782			Examples
783			--------
784			```python
785			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
786			GPath("/usr/bin").subpath_from("/usr/local/bin")  # None
787			GPath("/usr/bin").subpath_from("../Documents")    # None
788			```
789		"""
790		if not isinstance(base, GPath):
791			base = GPath(base, encoding=self._encoding)
792
793		if self.common_with(base, allow_current=True, allow_parents=False) is not None and self in base:
794			# If self._parent_level > base._parent_level, self is not in base, whereas if self._parent_level < base._parent_level, path from base to self's parent cannot be known
795			base_length = len(base._parts)
796			new_path = GPath(self)
797			new_path._parts = self._parts[base_length:]  # () when self == base
798			new_path._drive = ""
799			new_path._root = False
800			new_path._parent_level = 0
801			return new_path
802		else:
803			return None

Find the relative subpath from base to self if possible and if base contains self, or return None otherwise.

None will also be returned if there are unknown components in the subpath from base to self. For instance, if self is relative to the parent directory while base is relative to the grandparent directory, the path from the grandparent directory ../.. to the parent directory .. cannot be known.

Similar to relpath_from(), but self must be a descendent of base.

Parameters

base : the base path that the relative subpath should start from

Returns

GPath : relative subpath from base to self, which may be empty, if it exists

None : otherwise

Raises

ValueError if either self or base is an invalid GPath

Examples

GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
GPath("/usr/bin").subpath_from("/usr/local/bin")  # None
GPath("/usr/bin").subpath_from("../Documents")    # None
def relpath_from( self, origin: Union[GPath, str, bytes, os.PathLike]) -> Optional[GPath]:
806	def relpath_from(self, origin: GPathLike) -> Optional[GPath]:
807		"""
808			Find the relative path from `origin` to `self` if possible, or return None otherwise.
809
810			None will also be returned if there are unknown components in the relative path from `origin` to `self`. For instance, if `self` is relative to the parent directory while `base` base is relative to the grandparent directory, the path from the grandparent directory `../..` to the parent directory `..` cannot be known.
811
812			Similar to `subpath_from()`, but `self` does not need to be a descendent of `origin`.
813
814			Parameters
815			----------
816			`origin`
817			: the origin that the relative path should start from
818
819			Returns
820			-------
821			`GPath`
822			: relative path from `origin` to `self`, which may be empty, if it exists
823
824			`None`
825			: otherwise
826
827			Raises
828			------
829			`ValueError` if either `self` or `origin` is an invalid GPath
830
831			Examples
832			--------
833			```python
834			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
835			GPath("/usr/bin").subpath_from("/usr/local/bin")  # GPath("../../bin")
836			GPath("/usr/bin").subpath_from("../Documents")    # None
837			```
838		"""
839		self._validate()
840		if not isinstance(origin, GPath):
841			origin = GPath(origin, encoding=self._encoding)
842
843		if origin._root:
844			common = self.common_with(origin)
845			if common is None:
846				return None
847
848			new_path = GPath(self)
849			new_path._parent_level = len(origin) - len(common)
850			new_path._parts = self._parts[len(common):]
851			new_path._drive = ""
852			new_path._root = False
853			return new_path
854
855		else:
856			common = self.common_with(origin, allow_current=True, allow_parents=True)
857			if common is None:
858				return None
859			if common._parent_level > self._parent_level:
860				return None  # Path from common to self's parent cannot be known
861
862			# common._dotdot == self._dotdot
863			# origin._dotdot <= self._dotdot
864
865			new_path = GPath(self)
866			new_path._drive = ""
867			new_path._root = False
868			if len(common) == 0:
869				if origin._parent_level == self._parent_level:
870					new_path._parent_level = len(origin)
871				else:
872					new_path._parent_level = (common._parent_level - origin._parent_level) + len(origin)
873				new_path._parts = self._parts
874			else:
875				new_path._parent_level = len(origin) - len(common)
876				new_path._parts = self._parts[len(common):]
877
878			return new_path

Find the relative path from origin to self if possible, or return None otherwise.

None will also be returned if there are unknown components in the relative path from origin to self. For instance, if self is relative to the parent directory while base base is relative to the grandparent directory, the path from the grandparent directory ../.. to the parent directory .. cannot be known.

Similar to subpath_from(), but self does not need to be a descendent of origin.

Parameters

origin : the origin that the relative path should start from

Returns

GPath : relative path from origin to self, which may be empty, if it exists

None : otherwise

Raises

ValueError if either self or origin is an invalid GPath

Examples

GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
GPath("/usr/bin").subpath_from("/usr/local/bin")  # GPath("../../bin")
GPath("/usr/bin").subpath_from("../Documents")    # None
def render( self, platform: Union[str, platform.Platform, NoneType]) -> render.RenderedPath:
881	def render(self, platform: Union[str, Platform, None]) -> render.RenderedPath:
882		"""
883			Convert the path to a RenderedPath for printing in a specific target operating system.
884
885			This will convert, and coerce if necessary, the generalised abstract GPath into a platform-specific path which can then be converted to a printable string using <code>str(<var>renderred_path</var>)</code>. The resulting string will be in the format preferred by the target platform.
886
887			If the GPath contains features that the target platform does not support (such as drive name when the target platform is POSIX), and if there are no analogous features in the target platform, they will be dropped in the rendered path.
888
889			The rendered path also implements total ordering with binary comparisons, e.g. <code><var>r1</var> < <var>r2</var></code>, making it useful for sorting and collation. This ordering is done with platform-specific semantics, unlike GPath which does not have meaningful order.
890
891			Parameters
892			----------
893			`platform`
894			: the target platform where the path is to be used
895
896			Returns
897			-------
898			`RenderedPath`
899			: platform-specific path ready for sorting or output
900
901			Examples
902			--------
903			```python
904			# Print examples
905			print(GPath("/usr/bin").render('linux'))      # /usr/bin
906			print(GPath("/usr/bin").render('windows'))    # \\usr\\bin
907			print(GPath("C:/Windows").render('linux'))    # /Windows
908			print(GPath("C:/Windows").render('windows'))  # C:\\Windows
909
910			# Ordering examples
911			GPath("").render('linux') < GPath("abc").render('linux')       # True
912			GPath("abc").render('linux') < GPath("..").render('linux')     # True
913			GPath("..").render('linux') < GPath("../..").render('linux')   # True
914			GPath("../..").render('linux') < GPath("/").render('linux')    # True
915			GPath("/").render('linux') < GPath("C:/").render('linux')      # False
916			GPath("/").render('linux') <= GPath("C:/").render('linux')     # True
917			GPath("/").render('windows') < GPath("C:/").render('windows')  # True
918			```
919		"""
920		if platform is None:
921			platform = DEFAULT_PLATFORM
922		elif isinstance(platform, str):
923			platform = Platform.from_str(platform)
924		return render.get_type(platform)(self)

Convert the path to a RenderedPath for printing in a specific target operating system.

This will convert, and coerce if necessary, the generalised abstract GPath into a platform-specific path which can then be converted to a printable string using str(renderred_path). The resulting string will be in the format preferred by the target platform.

If the GPath contains features that the target platform does not support (such as drive name when the target platform is POSIX), and if there are no analogous features in the target platform, they will be dropped in the rendered path.

The rendered path also implements total ordering with binary comparisons, e.g. r1 < r2, making it useful for sorting and collation. This ordering is done with platform-specific semantics, unlike GPath which does not have meaningful order.

Parameters

platform : the target platform where the path is to be used

Returns

RenderedPath : platform-specific path ready for sorting or output

Examples

# Print examples
print(GPath("/usr/bin").render('linux'))      # /usr/bin
print(GPath("/usr/bin").render('windows'))    # \usr\bin
print(GPath("C:/Windows").render('linux'))    # /Windows
print(GPath("C:/Windows").render('windows'))  # C:\Windows

# Ordering examples
GPath("").render('linux') < GPath("abc").render('linux')       # True
GPath("abc").render('linux') < GPath("..").render('linux')     # True
GPath("..").render('linux') < GPath("../..").render('linux')   # True
GPath("../..").render('linux') < GPath("/").render('linux')    # True
GPath("/").render('linux') < GPath("C:/").render('linux')      # False
GPath("/").render('linux') <= GPath("C:/").render('linux')     # True
GPath("/").render('windows') < GPath("C:/").render('windows')  # True
def __hash__(self) -> int:
927	def __hash__(self) -> int:
928		"""
929			Calculate hash of the GPath object.
930
931			Usage: <code>hash(<var>g</var>)</code>
932		"""
933		return hash(self._tuple)

Calculate hash of the GPath object.

Usage: hash(g)

def __eq__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:
936	def __eq__(self, other: GPathLike) -> bool:  # type: ignore
937		"""
938			Check if two GPaths are completely identical.
939
940			Always return False if `other` is not a GPath object, even if it is a GPath-like object.
941
942			Usage: <code><var>g1</var> == <var>g2</var></code>
943
944			Examples
945			--------
946			```python
947			GPath("/usr/bin") == GPath("/usr/bin")  # True
948			GPath("/usr/bin") == GPath("usr/bin")   # False
949			GPath("C:/") == GPath("D:/")            # False
950			```
951		"""
952		if not isinstance(other, GPath):
953			other = GPath(other, encoding=self._encoding)
954		return self._tuple == other._tuple

Check if two GPaths are completely identical.

Always return False if other is not a GPath object, even if it is a GPath-like object.

Usage: g1 == g2

Examples

GPath("/usr/bin") == GPath("/usr/bin")  # True
GPath("/usr/bin") == GPath("usr/bin")   # False
GPath("C:/") == GPath("D:/")            # False
def __bool__(self) -> bool:
957	def __bool__(self) -> bool:
958		"""
959			False if `self` is a relative path without any relative components and without a drive, and True otherwise.
960
961			Usage: <code>bool(<var>g</var>)</code>, <code>not <var>g</var></code>, or <code>if <var>g</var>:</code>
962
963			Examples
964			--------
965			```python
966			bool(GPath("/"))    # True
967			bool(GPath(".."))   # True
968			bool(GPath("doc"))  # True
969			bool(GPath(""))     # False
970			```
971		"""
972		return self._root or self._drive != "" or self._parent_level != 0 or len(self._parts) > 0

False if self is a relative path without any relative components and without a drive, and True otherwise.

Usage: bool(g), not g, or if g:

Examples

bool(GPath("/"))    # True
bool(GPath(".."))   # True
bool(GPath("doc"))  # True
bool(GPath(""))     # False
def __str__(self) -> str:
975	def __str__(self) -> str:
976		"""
977			Return a platform-independent string representation of the path.
978
979			Usage: <code>str(<var>g</var>)</code>
980		"""
981		return str(self.render(Platform.GENERIC))

Return a platform-independent string representation of the path.

Usage: str(g)

def __repr__(self) -> str:
 984	def __repr__(self) -> str:
 985		"""
 986			Return a string that, when printed, gives the Python code associated with instantiating the GPath object.
 987
 988			Usage: <code>repr(<var>g</var>)</code>
 989		"""
 990		if self._platform is None:
 991			platform_repr = ""
 992		else:
 993			platform_repr = f", platform={repr(self._platform)}"
 994
 995		if self._encoding is None:
 996			encoding_repr = ""
 997		else:
 998			encoding_repr = f", encoding={repr(self._encoding)}"
 999
1000		if bool(self):
1001			return f"GPath({repr(str(self))}{platform_repr}{encoding_repr})"
1002		else:
1003			return f"GPath({repr('')}{platform_repr}{encoding_repr})"

Return a string that, when printed, gives the Python code associated with instantiating the GPath object.

Usage: repr(g)

def __len__(self) -> int:
1006	def __len__(self) -> int:
1007		"""
1008			Get the number of named path components, excluding any drive name or parent directories.
1009
1010			Usage: <code>len(<var>g</var>)</code>
1011
1012			Examples
1013			--------
1014			```python
1015			len(GPath("/usr/bin"))    # 2
1016			len(GPath("/"))           # 0
1017			len(GPath("C:/Windows"))  # 0
1018			len(GPath("C:/"))         # 0
1019			```
1020		"""
1021		return len(self._parts)

Get the number of named path components, excluding any drive name or parent directories.

Usage: len(g)

Examples

len(GPath("/usr/bin"))    # 2
len(GPath("/"))           # 0
len(GPath("C:/Windows"))  # 0
len(GPath("C:/"))         # 0
def __getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:
1024	def __getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:
1025		"""
1026			Get a 0-indexed named path component, or a slice of path components, excluding any drive name or parent directories.
1027
1028			Usage: <code><var>g</var>[<var>n</var>]</code>, <code><var>g</var>[<var>start</var>:<var>end</var>]</code>, <code><var>g</var>[<var>start</var>:<var>end</var>:<var>step</var>]</code>, etc.
1029
1030			Examples
1031			--------
1032			```python
1033			GPath("/usr/local/bin")[1]    # "local"
1034			GPath("/usr/local/bin")[-1]   # "bin"
1035			GPath("/usr/local/bin")[1:]   # ["local", "bin"]
1036			GPath("/usr/local/bin")[::2]  # ["usr", "bin"]
1037			```
1038		"""
1039		if isinstance(index, int):
1040			return self._parts[index]
1041		elif isinstance(index, slice):
1042			return list(self._parts[index])

Get a 0-indexed named path component, or a slice of path components, excluding any drive name or parent directories.

Usage: g[n], g[start:end], g[start:end:step], etc.

Examples

GPath("/usr/local/bin")[1]    # "local"
GPath("/usr/local/bin")[-1]   # "bin"
GPath("/usr/local/bin")[1:]   # ["local", "bin"]
GPath("/usr/local/bin")[::2]  # ["usr", "bin"]
def __iter__(self) -> Iterator[str]:
1045	def __iter__(self) -> Iterator[str]:
1046		"""
1047			Get an iterator through the named path components, excluding any drive name or parent directories.
1048
1049			Usage: <code>iter(<var>g</var>)</code> or <code>for <var>p</var> in <var>g</var>:</code>
1050		"""
1051		return iter(self._parts)

Get an iterator through the named path components, excluding any drive name or parent directories.

Usage: iter(g) or for p in g:

def __contains__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:
1054	def __contains__(self, other: GPathLike) -> bool:
1055		"""
1056			Check if the path represented by `self` contains the path represented by `other`; i.e. check if `self` is a parent directory of `other`.
1057
1058			Usage: <code><var>other</var> in <var>self</var></code>
1059
1060			Raises `ValueError` if either GPath is invalid
1061
1062			Examples
1063			--------
1064			```python
1065			GPath("/usr/local/bin") in GPath("/usr")  # True
1066			GPath("/usr/local/bin") in GPath("/bin")  # False
1067			GPath("..") in GPath("../..")             # True
1068			GPath("..") in GPath("C:/")               # False
1069			```
1070		"""
1071		if not isinstance(other, GPath):
1072			other = GPath(other, encoding=self._encoding)
1073
1074		common_path = self.common_with(other, allow_current=True, allow_parents=True)
1075		return common_path is not None and common_path == self

Check if the path represented by self contains the path represented by other; i.e. check if self is a parent directory of other.

Usage: other in self

Raises ValueError if either GPath is invalid

Examples

GPath("/usr/local/bin") in GPath("/usr")  # True
GPath("/usr/local/bin") in GPath("/bin")  # False
GPath("..") in GPath("../..")             # True
GPath("..") in GPath("C:/")               # False
def __add__( self, other: Union[GPath, str, bytes, os.PathLike]) -> GPath:
1078	def __add__(self, other: GPathLike) -> GPath:
1079		"""
1080			Add (concatenate) `other` to the end of `self`, and return a new copy.
1081
1082			If `other` is an absolute path, the returned path will be an absolute path that matches `other`, apart from the drive name.
1083
1084			If `other` has a drive, the returned path will have the same drive as `other`. Otherwise, the returned path will have the same drive as `self`. If neither has a drive, the returned path will not have a drive as well.
1085
1086			Alias: `__truediv__()`
1087
1088			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1089
1090			Raises `ValueError` if either GPath is invalid
1091
1092			Examples
1093			--------
1094			```python
1095			GPath("/usr") + GPath("local/bin")                   # GPath("/usr/local/bin")
1096			GPath("C:/Windows/System32") + GPath("../SysWOW64")  # GPath("C:/Windows/SysWOW64")
1097			GPath("C:/Windows/System32") + GPath("/usr/bin")     # GPath("C:/usr/bin")
1098			GPath("..") + GPath("../..")                         # GPath("../../..")
1099			GPath("..") / GPath("../..")                         # GPath("../../..")
1100			```
1101		"""
1102		if isinstance(other, GPath):
1103			other._validate
1104		else:
1105			other = GPath(other, encoding=self._encoding)
1106
1107		new_path = GPath(self)
1108		if other._root:
1109			new_path._parts = other._parts
1110			new_path._root = other._root
1111			new_path._parent_level = other._parent_level
1112		else:
1113			new_parts = [part for part in self._parts]
1114			for i in range(other._parent_level):
1115				if len(new_parts) > 0:
1116					new_parts.pop()
1117				elif not new_path._root:
1118					new_path._parent_level += 1
1119				else:
1120					pass  # parent of directory of root is still root
1121
1122			new_parts.extend(other._parts)
1123			new_path._parts = tuple(new_parts)
1124
1125		if other._drive != "":
1126			new_path._drive = other._drive
1127
1128		return new_path

Add (concatenate) other to the end of self, and return a new copy.

If other is an absolute path, the returned path will be an absolute path that matches other, apart from the drive name.

If other has a drive, the returned path will have the same drive as other. Otherwise, the returned path will have the same drive as self. If neither has a drive, the returned path will not have a drive as well.

Alias: __truediv__()

Usage: self + other or self / other

Raises ValueError if either GPath is invalid

Examples

GPath("/usr") + GPath("local/bin")                   # GPath("/usr/local/bin")
GPath("C:/Windows/System32") + GPath("../SysWOW64")  # GPath("C:/Windows/SysWOW64")
GPath("C:/Windows/System32") + GPath("/usr/bin")     # GPath("C:/usr/bin")
GPath("..") + GPath("../..")                         # GPath("../../..")
GPath("..") / GPath("../..")                         # GPath("../../..")
def __sub__(self, n: int) -> GPath:
1131	def __sub__(self, n: int) -> GPath:
1132		"""
1133			Remove `n` components from the end of the path and return a new copy.
1134
1135			Usage: <code><var>self</var> - <var>n</var></code>
1136
1137			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative
1138
1139			Examples
1140			--------
1141			```python
1142			GPath("C:/Windows/System32") - 1  # GPath("C:/Windows")
1143			GPath("/usr/bin") - 2             # GPath("/")
1144			GPath("Documents") - 3            # GPath("..")
1145			GPath("/") - 1                    # GPath("/")
1146			```
1147		"""
1148		if n < 0:
1149			raise ValueError("cannot subtract a negative number of components from the path: {n}; use __add__() instead")
1150
1151		new_path = GPath(self)
1152		new_parts = [part for part in self._parts]
1153		for i in range(n):
1154			if len(new_parts) > 0:
1155				new_parts.pop()
1156			elif not new_path._root:
1157				new_path._parent_level += 1
1158			else:
1159				pass  # removing components from root should still give root
1160		new_path._parts = tuple(new_parts)
1161		return new_path

Remove n components from the end of the path and return a new copy.

Usage: self - n

Raises ValueError if self is an invalid GPath or if n is negative

Examples

GPath("C:/Windows/System32") - 1  # GPath("C:/Windows")
GPath("/usr/bin") - 2             # GPath("/")
GPath("Documents") - 3            # GPath("..")
GPath("/") - 1                    # GPath("/")
def __mul__(self, n: int) -> GPath:
1164	def __mul__(self, n: int) -> GPath:
1165		"""
1166			Duplicate the named components of `self` `n` times and return a new path with the duplicated components.
1167
1168			Named components will be duplicated separately from the components representing a parent directory. If `self` is an absolute path, only the relative components will be duplicated.
1169
1170			If `n` is 0, the result is an empty path (either relative or absolute).
1171
1172			Usage: <code><var>self</var> * <var>n</var></code>
1173
1174			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative.
1175
1176			Examples
1177			--------
1178			```python
1179			GPath("/usr/bin") * 2    # GPath("/usr/bin/usr/bin")
1180			GPath("../docs") * 2     # GPath("../../docs/docs")
1181			GPath("C:/Windows") * 0  # GPath("C:/")
1182			```
1183		"""
1184		if n < 0:
1185			raise ValueError("cannot multiply path by a negative integer: {n}")
1186		new_path = GPath(self)
1187		new_path._parent_level = self._parent_level * n
1188		new_path._parts = self._parts * n
1189		return new_path

Duplicate the named components of self n times and return a new path with the duplicated components.

Named components will be duplicated separately from the components representing a parent directory. If self is an absolute path, only the relative components will be duplicated.

If n is 0, the result is an empty path (either relative or absolute).

Usage: self * n

Raises ValueError if self is an invalid GPath or if n is negative.

Examples

GPath("/usr/bin") * 2    # GPath("/usr/bin/usr/bin")
GPath("../docs") * 2     # GPath("../../docs/docs")
GPath("C:/Windows") * 0  # GPath("C:/")
def __truediv__( self, other: Union[GPath, str, bytes, os.PathLike]) -> GPath:
1192	def __truediv__(self, other: GPathLike) -> GPath:
1193		"""
1194			Alias of `__add__()`.
1195
1196			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1197		"""
1198		return self.__add__(other)

Alias of __add__().

Usage: self + other or self / other

def __and__( self, other: Union[GPath, str, bytes, os.PathLike]) -> Optional[GPath]:
1201	def __and__(self, other: GPathLike) -> Union[GPath, None]:
1202		"""
1203			Equivalent to `self.common_with(other)`, using the default options of `common_with()`.
1204
1205			Usage: <code><var>g1</var> & <var>g2</var></code>
1206		"""
1207		return self.common_with(other)

Equivalent to self.common_with(other), using the default options of common_with().

Usage: g1 & g2

def __lshift__(self, n: int) -> GPath:
1210	def __lshift__(self, n: int) -> GPath:
1211		"""
1212			Move the imaginary current working directory `n` steps up the filesystem tree.
1213
1214			If `self` is a relative path, remove up to `n` levels of parent directories from the start of the path and return a copy. If it is an absolute path, return a copy of `self` unchanged.
1215
1216			If `n` is negative, this is equivalent to `__rshift__(-n)`.
1217
1218			Usage: <code><var>self</var> << <var>n</var></code>
1219
1220			Raises `ValueError` if `self` is an invalid GPath.
1221
1222			Examples
1223			--------
1224			```python
1225			GPath("../SysWOW64/drivers") << 1  # GPath("SysWOW64/drivers")
1226			GPath("../doc") << 2               # GPath("doc")
1227			GPath("/usr/bin") << 2             # GPath("/usr/bin")
1228			```
1229		"""
1230		if n < 0:
1231			return self.__rshift__(-1 * n)
1232		new_path = GPath(self)
1233		if not new_path._root:
1234			new_path._parent_level = max(new_path._parent_level - n, 0)
1235		return new_path

Move the imaginary current working directory n steps up the filesystem tree.

If self is a relative path, remove up to n levels of parent directories from the start of the path and return a copy. If it is an absolute path, return a copy of self unchanged.

If n is negative, this is equivalent to __rshift__(-n).

Usage: self << n

Raises ValueError if self is an invalid GPath.

Examples

GPath("../SysWOW64/drivers") << 1  # GPath("SysWOW64/drivers")
GPath("../doc") << 2               # GPath("doc")
GPath("/usr/bin") << 2             # GPath("/usr/bin")
def __rshift__(self, n: int) -> GPath:
1238	def __rshift__(self, n: int) -> GPath:
1239		"""
1240			Move the imaginary current working directory `n` steps down the filesystem tree.
1241
1242			If `self` is a relative path, add `n` levels of parent directories to the start of the path and return a copy. If it is an absolute path, return a copy of `self` unchanged.
1243
1244			If `n` is negative, this is equivalent to `__lshift__(-n)`.
1245
1246			Usage: <code><var>self</var> >> <var>n</var></code>
1247
1248			Raises `ValueError` if `self` is an invalid GPath
1249
1250			Examples
1251			--------
1252			```python
1253			GPath("../SysWOW64/drivers") >> 1  # GPath("../../SysWOW64/drivers")
1254			GPath("/usr/bin") >> 2             # GPath("/usr/bin")
1255			```
1256		"""
1257		if n < 0:
1258			return self.__lshift__(-1 * n)
1259		new_path = GPath(self)
1260		if not new_path._root:
1261			new_path._parent_level += n
1262		return new_path

Move the imaginary current working directory n steps down the filesystem tree.

If self is a relative path, add n levels of parent directories to the start of the path and return a copy. If it is an absolute path, return a copy of self unchanged.

If n is negative, this is equivalent to __lshift__(-n).

Usage: self >> n

Raises ValueError if self is an invalid GPath

Examples

GPath("../SysWOW64/drivers") >> 1  # GPath("../../SysWOW64/drivers")
GPath("/usr/bin") >> 2             # GPath("/usr/bin")
Inherited Members
collections.abc.Hashable
__subclasshook__
collections.abc.Iterable
__class_getitem__
builtins.object
__new__
__getattribute__
__setattr__
__delattr__
__lt__
__le__
__ne__
__gt__
__ge__
__reduce_ex__
__reduce__
__getstate__
__init_subclass__
__format__
__sizeof__
__dir__
GPathLike = Union[GPath, str, bytes, os.PathLike]