Edit on GitHub

gpath

1__version__ = '0.4.3'
2
3from ._gpath import GPath, GPathLike
4
5__all__ = ('GPath', 'GPathLike')
class GPath(Hashable, Sized, Iterable):
  84class GPath(Hashable, Sized, Iterable):
  85	"""
  86		An immutable generalised abstract file path that has no dependency on any real filesystem.
  87
  88		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.
  89
  90		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.
  91
  92		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.
  93	"""
  94
  95	__slots__ = (
  96		'_parts',
  97		'_root',
  98		'_drive',
  99		'_parent_level',
 100		'_encoding',
 101	)
 102
 103
 104	def __init__(self, path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None):
 105		"""
 106			Initialise a normalised and generalised abstract file path, possibly by copying an existing GPath object.
 107
 108			Parameters
 109			----------
 110			`path`
 111			: path-like object representing a (possibly unnormalised) file path, or a GPath object to be copied
 112
 113			`​encoding`
 114			: 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 name should be one of the standard Python text encodings, as listed in the `codecs` module of the standard library. The specified encoding will propagate to new GPaths that result from operations on this GPath. If a binary operation involves two GPaths, the encoding specified by the left operand will be propagated to the result.
 115
 116			Raises
 117			------
 118			`ValueError` if `other` is an invalid GPath
 119
 120			Examples
 121			--------
 122			```python
 123			GPath("/")
 124			GPath("/usr/bin")
 125			GPath("C:/Program Files")
 126			```
 127		"""
 128
 129		self._parts: tuple[str, ...] = tuple()  # root- or parent- relative path
 130		self._root: bool = False
 131		self._drive: str = ""
 132		self._parent_level: int = 0
 133
 134		self._encoding: Optional[str] = encoding
 135
 136		if path is None or path == "":
 137			return
 138
 139		if isinstance(path, GPath):
 140			path._validate()
 141			self._parts = path._parts
 142			self._root = path._root
 143			self._drive = path._drive
 144			self._parent_level = path._parent_level
 145
 146			self._encoding = path._encoding if encoding is None else encoding
 147			return
 148
 149		path = os.fspath(path)
 150
 151		if isinstance(path, bytes):
 152			if self._encoding is None:
 153				path = path.decode(DEFAULT_ENCODING)
 154			else:
 155				path = path.decode(self._encoding)
 156
 157		# path is a str
 158
 159		if len(path) >= 2 and path[1] in _rules.generic_rules.drive_postfixes:
 160			self._drive = path[0]
 161			driveless_path = path[2:]
 162		else:
 163			driveless_path = path
 164
 165		for root in _rules.generic_rules.roots:
 166			if driveless_path.startswith(root):
 167				self._root = True
 168				break
 169
 170		if self._root:
 171			rootless_path = driveless_path[1:]
 172		else:
 173			rootless_path = driveless_path
 174
 175
 176		parts = _split_relative(rootless_path, delimiters=(set(_rules.generic_rules.separators) | set(_rules.generic_rules.separators)))
 177		parts = _normalise_relative(parts)
 178		parent_level = 0
 179		while parent_level < len(parts) and parts[parent_level] in _rules.generic_rules.parent_indicators:
 180			parent_level += 1
 181		self._parts = tuple(parts[parent_level:])
 182		if self._root == False:
 183			self._parent_level = parent_level
 184
 185
 186	@property
 187	def named_parts(self) -> list[str]:
 188		"""
 189			Read-only named components of the path, not including the filesystem root, drive name, or any parent directories
 190
 191			Examples
 192			--------
 193			```python
 194			GPath("usr/local/bin").named_parts     # ["usr", "local", "bin"]
 195			GPath("../../Documents").named_parts   # ["Documents"]
 196			GPath("/usr/bin").named_parts          # ["usr", "bin"]
 197			GPath("C:/Program Files").named_parts  # ["Program Files"]
 198			```
 199		"""
 200		return list(self._parts)
 201
 202	@property
 203	def parent_level(self) -> int:
 204		"""
 205			Read-only number of levels of parent directories that the path is relative to, which may be 0
 206
 207			Examples
 208			--------
 209			```python
 210			GPath("../../Documents").parent_level  # 2
 211			GPath("usr/local/bin").parent_level    # 0
 212			```
 213		"""
 214		return self._parent_level
 215
 216	@property
 217	def parent_parts(self) -> list[str]:
 218		"""
 219			Read-only path components representing a parent directory that it is relative to, if any, with one item for each level of parent directory
 220
 221			Examples
 222			--------
 223			```python
 224			GPath("../../Documents").parent_parts  # ["..", ".."]
 225			GPath("usr/local/bin").parent_parts    # []
 226			```
 227		"""
 228		return [_rules.generic_rules.parent_indicators[0] for i in range(self._parent_level)]
 229
 230	@property
 231	def relative_parts(self) -> list[str]:
 232		"""
 233			Read-only relative components of the path, not including the filesystem root or drive name, including one item for each level of parent directory
 234
 235			Examples
 236			--------
 237			```python
 238			GPath("usr/local/bin").relative_parts     # ["usr", "local", "bin"]
 239			GPath("../../Documents").relative_parts   # ["..", "..", "Documents"]
 240			GPath("/usr/bin").relative_parts          # ["usr", "bin"]
 241			GPath("C:/Program Files").relative_parts  # ["Program Files"]
 242			```
 243		"""
 244		return self.parent_parts + list(self._parts)
 245
 246	@property
 247	def drive(self) -> str:
 248		"""
 249			Read-only drive name
 250
 251			Examples
 252			--------
 253			```python
 254			GPath("C:/Windows").drive       # "C:"
 255			GPath("/usr/bin").drive         # ""
 256			GPath("../../Documents").drive  # ""
 257			```
 258		"""
 259		return self._drive
 260
 261	@property
 262	def absolute(self) -> bool:
 263		"""
 264			Read-only flag for whether the path is an absolute path
 265
 266			Examples
 267			--------
 268			```python
 269			GPath("/").absolute                # True
 270			GPath("C:/Windows").absolute       # True
 271			GPath("local/bin").absolute        # False
 272			GPath("../../Documents").absolute  # False
 273			```
 274		"""
 275		return self._root
 276
 277	@property
 278	def root(self) -> bool:
 279		"""
 280			Read-only flag for whether the path is exactly the root of the filesystem
 281
 282			Examples
 283			--------
 284			```python
 285			GPath("/").root                # True
 286			GPath("C:/").root              # True
 287			GPath("/usr/bin").root         # False
 288			GPath("C:/Windows").root       # False
 289			GPath("../../Documents").root  # False
 290			```
 291		"""
 292		return self._root and len(self._parts) == 0
 293
 294	@property
 295	def encoding(self) -> Union[str, None]:
 296		"""
 297			Read-only encoding used to decode other paths that are given as bytes-like objects, or None if the default should be used
 298		"""
 299		return self._encoding
 300
 301
 302	#@overload
 303	#@staticmethod
 304	#def partition(paths: Iterable[GPathLike], /, *, allow_current, allow_parents, encoding) -> dict[GPath, list[GPath]]:
 305	#	...
 306	#@overload
 307	#@staticmethod
 308	#def partition(*paths: GPathLike, allow_current, allow_parents, encoding) -> dict[GPath, list[GPath]]:
 309	#	...
 310	@staticmethod
 311	def partition(*paths, allow_current: bool=True, allow_parents: bool=True, encoding: Optional[str]=None) -> dict[GPath, list[GPath]]:
 312		"""
 313			Partition a collection of paths based on shared common base paths such that each path belongs to one partition.
 314
 315			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.
 316
 317			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.
 318
 319			Parameters
 320			----------
 321			`paths: Iterable[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
 322			: the paths to be partitioned, which can be given as either a list-like object or as variadic arguments
 323
 324			`allow_current`
 325			: whether non-parent relative paths with no shared components should be considered to have a common base path (see `common_with()`)
 326
 327			`allow_parents`
 328			: 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.
 329
 330			`​encoding`
 331			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
 332
 333			Returns
 334			-------
 335			a dictionary that maps the common base path of each partition to a list of relative paths
 336
 337			Raises
 338			------
 339			  `ValueError`
 340			  if any of the GPaths are invalid
 341
 342			Examples
 343			--------
 344			```python
 345			GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")
 346
 347			assert partitions == {
 348				GPath("/usr")      : [GPath("bin"), GPath("local")],
 349				GPath("../../doc") : [GPath("")],
 350				GPath("C:/")       : [GPath("Windows"), GPath("Program Files")],
 351			}
 352			```
 353		"""
 354		flattened_paths: list[GPathLike] = []
 355		for path_or_list in paths:
 356			if _is_gpathlike(path_or_list):
 357				flattened_paths.append(path_or_list)
 358			else:
 359				flattened_paths.extend(path_or_list)
 360		gpaths = [path if isinstance(path, GPath) else GPath(path, encoding=encoding) for path in flattened_paths]
 361
 362		partition_map = {}
 363		if len(gpaths) > 0:
 364			if allow_parents == True:
 365				partition_map[gpaths[0]] = []
 366			else:
 367				partition_map[gpaths[0]] = [gpaths[0]]
 368
 369		for path in gpaths[1:]:
 370			partition_found = False
 371			for partition in partition_map:
 372				candidate_common = partition.common_with(path, allow_current=allow_current, allow_parents=allow_parents)
 373				if candidate_common is not None:
 374					partition_found = True
 375					if candidate_common != partition:
 376						partition_map[candidate_common] = partition_map[partition]
 377						del partition_map[partition]
 378					if allow_parents == False:
 379						partition_map[candidate_common].append(path)
 380					break
 381			if not partition_found:
 382				if allow_parents == True:
 383					partition_map[path] = []
 384				else:
 385					partition_map[path] = [path]
 386
 387		for partition, path_list in partition_map.items():
 388			partition_map[partition] = [path.subpath_from(partition) for path in path_list]
 389
 390		return partition_map
 391
 392
 393	#@overload
 394	#@staticmethod
 395	#def join(paths: Iterable[GPathLike], /, *, encoding) -> GPath:
 396	#	...
 397	#@overload
 398	#@staticmethod
 399	#def join(*paths: GPathLike, encoding) -> GPath:
 400	#	...
 401	@staticmethod
 402	def join(*paths, encoding: Optional[str]=None) -> GPath:
 403		"""
 404			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.
 405
 406			Parameters
 407			----------
 408			`paths`: `Sequence[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
 409			: the paths to be combined, which can be given as either a list-like object or as variadic arguments
 410
 411			`​encoding`
 412			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
 413
 414			Returns
 415			-------
 416			the combined path
 417
 418			Raises
 419			------
 420			`ValueError` if any of the GPaths are invalid
 421
 422			Examples
 423			--------
 424			```python
 425			GPath.join("usr", "local", "bin")          # GPath("usr/local/bin")
 426			GPath.join("/usr/local/bin", "../../bin")  # GPath("/usr/bin")
 427			GPath.join("C:/", "Windows")               # GPath("C:/Windows")
 428			```
 429		"""
 430		flattened_paths: list[GPathLike] = []
 431		for path_or_list in paths:
 432			if _is_gpathlike(path_or_list):
 433				flattened_paths.append(path_or_list)
 434			else:
 435				flattened_paths.extend(path_or_list)
 436
 437		if len(flattened_paths) == 0:
 438			return GPath(encoding=encoding)
 439
 440		combined_path = flattened_paths[0]
 441		if not isinstance(combined_path, GPath):
 442			combined_path = GPath(combined_path, encoding=encoding)
 443		for path in flattened_paths[1:]:
 444			combined_path = combined_path + path
 445
 446		return combined_path
 447
 448
 449	def as_relative(self, parent_level: Optional[int]=None) -> GPath:
 450		"""
 451			Convert the path to a relative path and return a new copy.
 452
 453			Parameters
 454			----------
 455			`​parent_level`
 456			: 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.
 457
 458			Raises
 459			------
 460			`TypeError` if `​parent_level` is not a valid type
 461
 462			Examples
 463			--------
 464			```python
 465			GPath("/usr/bin").as_relative()      # GPath("usr/bin")
 466			GPath("C:/Windows").as_relative()    # GPath("C:Windows")
 467			GPath("../Documents").as_relative()  # GPath("../Documents")
 468			```
 469		"""
 470
 471		new_path = GPath(self)
 472		new_path._root = False
 473		if parent_level is None:
 474			pass
 475		elif isinstance(parent_level, int):
 476			new_path._parent_level = parent_level
 477		else:
 478			raise TypeError(f"parent_level must be an int: {parent_level} ({type(parent_level)})")
 479
 480		return new_path
 481
 482
 483	def as_absolute(self) -> GPath:
 484		"""
 485			Convert the path to an absolute path and return a new copy.
 486
 487			Any parent directory that the path is relative to will be removed. If the path is already absolute, an identical copy is returned.
 488
 489			Examples
 490			--------
 491			```python
 492			GPath("usr/bin").as_absolute()       # GPath("/usr/bin")
 493			GPath("../Documents").as_absolute()  # GPath("/Documents")
 494			GPath("C:Windows").as_absolute()     # GPath("C:/Windows")
 495			```
 496		"""
 497		new_path = GPath(self)
 498		new_path._root = True
 499		new_path._parent_level = 0
 500		return new_path
 501
 502
 503	def with_drive(self, drive: Union[str, bytes, None]=None) -> GPath:
 504		"""
 505			Return a new copy of the path with the drive set to `​drive`.
 506
 507			If `​drive` is `""` or None, this would be equivalent to `without_drive()`.
 508
 509			Parameters
 510			----------
 511			`​drive`
 512			: the drive for the returned path, or either `""` or None if the returned path should have no drive
 513
 514			Returns
 515			-------
 516			`GPath`
 517			: a new path with the given drive
 518
 519			Raises
 520			------
 521			- `TypeError` if `​drive` is not a valid type
 522			- `ValueError` if `​drive` has more than one character
 523
 524			Examples
 525			--------
 526			```python
 527			GPath("C:/Windows").with_drive()      # GPath("/Windows")
 528			GPath("C:/Windows").with_drive("D")   # GPath("D:/Windows")
 529			GPath("/Windows").with_drive("C")     # GPath("C:/Windows")
 530			```
 531		"""
 532		if drive is None:
 533			drive = ""
 534		elif isinstance(drive, bytes):
 535			if self._encoding is None:
 536				drive = drive.decode(DEFAULT_ENCODING)
 537			else:
 538				drive = drive.decode(self._encoding)
 539		elif isinstance(drive, str):
 540			pass
 541		else:
 542			raise TypeError(f"drive must be a str or bytes object: {drive} ({type(drive)})")
 543
 544		if len(drive) > 1:
 545			raise ValueError(f"drive can only be a single character, an empty string or None: {drive}")
 546
 547		new_path = GPath(self)
 548		new_path._drive = drive
 549		return new_path
 550
 551
 552	def without_drive(self) -> GPath:
 553		"""
 554			Return a new copy of the path without a drive.
 555
 556			Equivalent to `with_drive("")` or `with_drive(None)`.
 557
 558			Returns
 559			-------
 560			`GPath`
 561			: a new path without a drive
 562
 563			Examples
 564			--------
 565			```python
 566			GPath("C:/Windows").without_drive()      # GPath("/Windows")
 567			```
 568		"""
 569		return self.with_drive(None)
 570
 571
 572	def common_with(self, other: GPathLike, allow_current: bool=True, allow_parents: bool=False) -> Optional[GPath]:
 573		"""
 574			Find the longest common base path shared between `self` and `other`, or return None if no such path exists.
 575
 576			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.
 577
 578			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>).
 579
 580			Parameters
 581			----------
 582			`other`
 583			: the path to compare with
 584
 585			`allow_current`
 586			: 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.
 587
 588			`allow_parents`
 589			: 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.
 590
 591			Returns
 592			-------
 593			`GPath`
 594			: the longest common base path, which may be empty, if it exists
 595
 596			`None`
 597			: otherwise
 598
 599			Raises
 600			------
 601			`ValueError` if either `self` or `other` is an invalid GPath
 602
 603			Examples
 604			--------
 605			```python
 606			GPath("/usr/bin").find_common("/usr/local/bin")               # GPath("/usr")
 607			GPath("C:/Windows/System32").find_common("C:/Program Files")  # GPath("C:/")
 608			GPath("../Documents").find_common("../Pictures")              # GPath("..")
 609			```
 610		"""
 611		self._validate()
 612		if isinstance(other, GPath):
 613			other._validate()
 614		else:
 615			other = GPath(other, encoding=self._encoding)
 616
 617		if self._drive != other._drive:
 618			return None
 619		if self._root != other._root:
 620			return None
 621
 622		if allow_parents:
 623			allow_current = True
 624
 625		parts = []
 626		if self._root:
 627			common_path = GPath(self)
 628			for part1, part2 in zip(self._parts, other._parts):
 629				if part1 == part2:
 630					parts.append(part1)
 631		else:
 632			if self._parent_level != other._parent_level:
 633				if not allow_parents:
 634					return None
 635
 636				common_path = GPath(self)
 637				common_path._parent_level = max(self._parent_level, other._parent_level)
 638			else:
 639				common_path = GPath(self)
 640				for part1, part2 in zip(self._parts, other._parts):
 641					if part1 == part2:
 642						parts.append(part1)
 643
 644		common_path._parts = tuple(parts)
 645
 646		if not allow_current and not bool(common_path):
 647			if common_path != self or common_path != other:
 648				return None
 649		return common_path
 650
 651
 652	def subpath_from(self, base: GPathLike) -> Optional[GPath]:
 653		"""
 654			Find the relative subpath from `base` to `self` if possible and if `base` contains `self`, or return None otherwise.
 655
 656			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.
 657
 658			Similar to `relpath_from()`, but `self` must be a descendent of `base`.
 659
 660			Parameters
 661			----------
 662			`base`
 663			: the base path that the relative subpath should start from
 664
 665			Returns
 666			-------
 667			`GPath`
 668			: relative subpath from `base` to `self`, which may be empty, if it exists
 669
 670			`None`
 671			: otherwise
 672
 673			Raises
 674			------
 675			`ValueError` if either `self` or `base` is an invalid GPath
 676
 677			Examples
 678			--------
 679			```python
 680			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
 681			GPath("/usr/bin").subpath_from("/usr/local/bin")  # None
 682			GPath("/usr/bin").subpath_from("../Documents")    # None
 683			```
 684		"""
 685		if not isinstance(base, GPath):
 686			base = GPath(base, encoding=self._encoding)
 687
 688		if self.common_with(base, allow_current=True, allow_parents=False) is not None and self in base:
 689			# 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
 690			base_length = len(base._parts)
 691			new_path = GPath(self)
 692			new_path._parts = self._parts[base_length:]  # () when self == base
 693			new_path._drive = ""
 694			new_path._root = False
 695			new_path._parent_level = 0
 696			return new_path
 697		else:
 698			return None
 699
 700
 701	def relpath_from(self, origin: GPathLike) -> Optional[GPath]:
 702		"""
 703			Find the relative path from `origin` to `self` if possible, or return None otherwise.
 704
 705			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.
 706
 707			Similar to `subpath_from()`, but `self` does not need to be a descendent of `origin`.
 708
 709			Parameters
 710			----------
 711			`origin`
 712			: the origin that the relative path should start from
 713
 714			Returns
 715			-------
 716			`GPath`
 717			: relative path from `origin` to `self`, which may be empty, if it exists
 718
 719			`None`
 720			: otherwise
 721
 722			Raises
 723			------
 724			`ValueError` if either `self` or `origin` is an invalid GPath
 725
 726			Examples
 727			--------
 728			```python
 729			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
 730			GPath("/usr/bin").subpath_from("/usr/local/bin")  # GPath("../../bin")
 731			GPath("/usr/bin").subpath_from("../Documents")    # None
 732			```
 733		"""
 734		self._validate()
 735		if not isinstance(origin, GPath):
 736			origin = GPath(origin, encoding=self._encoding)
 737
 738		if origin._root:
 739			common = self.common_with(origin)
 740			if common is None:
 741				return None
 742
 743			new_path = GPath(self)
 744			new_path._parent_level = len(origin) - len(common)
 745			new_path._parts = self._parts[len(common):]
 746			new_path._drive = ""
 747			new_path._root = False
 748			return new_path
 749
 750		else:
 751			common = self.common_with(origin, allow_current=True, allow_parents=True)
 752			if common is None:
 753				return None
 754			if common._parent_level > self._parent_level:
 755				return None  # Path from common to self's parent cannot be known
 756
 757			# common._dotdot == self._dotdot
 758			# origin._dotdot <= self._dotdot
 759
 760			new_path = GPath(self)
 761			new_path._drive = ""
 762			new_path._root = False
 763			if len(common) == 0:
 764				if origin._parent_level == self._parent_level:
 765					new_path._parent_level = len(origin)
 766				else:
 767					new_path._parent_level = (common._parent_level - origin._parent_level) + len(origin)
 768				new_path._parts = self._parts
 769			else:
 770				new_path._parent_level = len(origin) - len(common)
 771				new_path._parts = self._parts[len(common):]
 772
 773			return new_path
 774
 775
 776	def __hash__(self) -> int:
 777		"""
 778			Calculate hash of the GPath object.
 779
 780			Usage: <code>hash(<var>g</var>)</code>
 781		"""
 782		return hash(self._tuple)
 783
 784
 785	def __eq__(self, other: GPathLike) -> bool:
 786		"""
 787			Check if two GPaths are completely identical.
 788
 789			Always return False if `other` is not a GPath object, even if it is a GPath-like object.
 790
 791			Usage: <code><var>g1</var> == <var>g2</var></code>
 792
 793			Examples
 794			--------
 795			```python
 796			GPath("/usr/bin") == GPath("/usr/bin")  # True
 797			GPath("/usr/bin") == GPath("usr/bin")   # False
 798			GPath("C:/") == GPath("D:/")            # False
 799			```
 800		"""
 801		if not isinstance(other, GPath):
 802			other = GPath(other, encoding=self._encoding)
 803		return self._tuple == other._tuple
 804
 805
 806	def __bool__(self) -> bool:
 807		"""
 808			Truthy if `self` is an absolute path, if `self` is relative to a parent directory, or if `self` has at least one named component.
 809
 810			Usage: <code>bool(<var>g</var>)</code>, <code>not <var>g</var></code>, or <code>if <var>g</var>:</code>
 811
 812			Examples
 813			--------
 814			```python
 815			bool(GPath("/"))    # True
 816			bool(GPath(".."))   # True
 817			bool(GPath("doc"))  # True
 818			bool(GPath(""))     # False
 819			```
 820		"""
 821		return self._root or self._drive != "" or self._parent_level != 0 or len(self._parts) > 0
 822
 823
 824	def __str__(self) -> str:
 825		"""
 826			Return a string representation of the path.
 827
 828			Usage: <code>str(<var>g</var>)</code>
 829		"""
 830		if bool(self):
 831			if self.root and self._drive == "":
 832				return _rules.generic_rules.roots[0]
 833			else:
 834				return (self._drive + _rules.generic_rules.drive_postfixes[0] if self._drive != "" else "") + (_rules.generic_rules.roots[0] if self._root else "") + _rules.generic_rules.separators[0].join(self.relative_parts)
 835		else:
 836			return _rules.generic_rules.current_indicators[0]
 837
 838
 839	def __repr__(self) -> str:
 840		"""
 841			Return a string that, when printed, gives the Python code associated with instantiating the GPath object.
 842
 843			Usage: <code>repr(<var>g</var>)</code>
 844		"""
 845		if self._encoding is None:
 846			encoding_repr = ""
 847		else:
 848			encoding_repr = f", encoding={repr(self._encoding)}"
 849
 850		if bool(self):
 851			return f"GPath({repr(str(self))}{encoding_repr})"
 852		else:
 853			return f"GPath({repr('')}{encoding_repr})"
 854
 855
 856	def __len__(self) -> int:
 857		"""
 858			Get the number of named path components, excluding any drive name or parent directories.
 859
 860			Usage: <code>len(<var>g</var>)</code>
 861
 862			Examples
 863			--------
 864			```python
 865			len(GPath("/usr/bin"))    # 2
 866			len(GPath("/"))           # 0
 867			len(GPath("C:/Windows"))  # 0
 868			len(GPath("C:/"))         # 0
 869			```
 870		"""
 871		return len(self._parts)
 872
 873
 874	def __getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:
 875		"""
 876			Get a 0-indexed named path component, or a slice of path components, excluding any drive name or parent directories.
 877
 878			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.
 879
 880			Examples
 881			--------
 882			```python
 883			GPath("/usr/local/bin")[1]    # "local"
 884			GPath("/usr/local/bin")[-1]   # "bin"
 885			GPath("/usr/local/bin")[1:]   # ["local", "bin"]
 886			GPath("/usr/local/bin")[::2]  # ["usr", "bin"]
 887			```
 888		"""
 889		if isinstance(index, int):
 890			return self._parts[index]
 891		elif isinstance(index, slice):
 892			return list(self._parts[index])
 893
 894
 895	def __iter__(self) -> Iterator[str]:
 896		"""
 897			Get an iterator through the named path components, excluding any drive name or parent directories.
 898
 899			Usage: <code>iter(<var>g</var>)</code> or <code>for <var>p</var> in <var>g</var>:</code>
 900		"""
 901		return iter(self._parts)
 902
 903
 904	def __contains__(self, other: GPathLike) -> bool:
 905		"""
 906			Check if the path represented by `self` contains the path represented by `other`; i.e. check if `self` is a parent directory of `other`.
 907
 908			Usage: <code><var>other</var> in <var>self</var></code>
 909
 910			Raises `ValueError` if either GPath is invalid
 911
 912			Examples
 913			--------
 914			```python
 915			GPath("/usr/local/bin") in GPath("/usr")  # True
 916			GPath("/usr/local/bin") in GPath("/bin")  # False
 917			GPath("..") in GPath("../..")             # True
 918			GPath("..") in GPath("C:/")               # False
 919			```
 920		"""
 921		if not isinstance(other, GPath):
 922			other = GPath(other, encoding=self._encoding)
 923
 924		common_path = self.common_with(other, allow_current=True, allow_parents=True)
 925		return common_path is not None and common_path == self
 926
 927
 928	def __add__(self, other: GPathLike) -> GPath:
 929		"""
 930			Add (concatenate) `other` to the end of `self`, and return a new copy.
 931
 932			If `other` is an absolute path, the returned path will be an absolute path that matches `other`, apart from the drive name.
 933
 934			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.
 935
 936			Alias: `__truediv__()`
 937
 938			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
 939
 940			Raises `ValueError` if either GPath is invalid
 941
 942			Examples
 943			--------
 944			```python
 945			GPath("/usr") + GPath("local/bin")                   # GPath("/usr/local/bin")
 946			GPath("C:/Windows/System32") + GPath("../SysWOW64")  # GPath("C:/Windows/SysWOW64")
 947			GPath("C:/Windows/System32") + GPath("/usr/bin")     # GPath("C:/usr/bin")
 948			GPath("..") + GPath("../..")                         # GPath("../../..")
 949			GPath("..") / GPath("../..")                         # GPath("../../..")
 950			```
 951		"""
 952		if isinstance(other, GPath):
 953			other._validate
 954		else:
 955			other = GPath(other, encoding=self._encoding)
 956
 957		new_path = GPath(self)
 958		if other._root:
 959			new_path._parts = other._parts
 960			new_path._root = other._root
 961			new_path._parent_level = other._parent_level
 962		else:
 963			new_parts = [part for part in self._parts]
 964			for i in range(other._parent_level):
 965				if len(new_parts) > 0:
 966					new_parts.pop()
 967				elif not new_path._root:
 968					new_path._parent_level += 1
 969				else:
 970					pass  # parent of directory of root is still root
 971
 972			new_parts.extend(other._parts)
 973			new_path._parts = tuple(new_parts)
 974
 975		if other._drive != "":
 976			new_path._drive = other._drive
 977
 978		return new_path
 979
 980
 981	def __sub__(self, n: int) -> GPath:
 982		"""
 983			Remove `n` components from the end of the path and return a new copy.
 984
 985			Usage: <code><var>self</var> - <var>n</var></code>
 986
 987			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative
 988
 989			Examples
 990			--------
 991			```python
 992			GPath("C:/Windows/System32") - 1  # GPath("C:/Windows")
 993			GPath("/usr/bin") - 2             # GPath("/")
 994			GPath("Documents") - 3            # GPath("..")
 995			GPath("/") - 1                    # GPath("/")
 996			```
 997		"""
 998		if n < 0:
 999			raise ValueError("cannot subtract a negative number of components from the path: {n}; use __add__() instead")
1000
1001		new_path = GPath(self)
1002		new_parts = [part for part in self._parts]
1003		for i in range(n):
1004			if len(new_parts) > 0:
1005				new_parts.pop()
1006			elif not new_path._root:
1007				new_path._parent_level += 1
1008			else:
1009				pass  # removing components from root should still give root
1010		new_path._parts = tuple(new_parts)
1011		return new_path
1012
1013
1014	def __mul__(self, n: int) -> GPath:
1015		"""
1016			Duplicate the named components of `self` `n` times and return a new path with the duplicated components.
1017
1018			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.
1019
1020			If `n` is 0, the result is an empty path (either relative or absolute).
1021
1022			Usage: <code><var>self</var> * <var>n</var></code>
1023
1024			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative.
1025
1026			Examples
1027			--------
1028			```python
1029			GPath("/usr/bin") * 2    # GPath("/usr/bin/usr/bin")
1030			GPath("../docs") * 2     # GPath("../../docs/docs")
1031			GPath("C:/Windows") * 0  # GPath("C:/")
1032			```
1033		"""
1034		if n < 0:
1035			raise ValueError("cannot multiply path by a negative integer: {n}")
1036		new_path = GPath(self)
1037		new_path._parent_level = self._parent_level * n
1038		new_path._parts = self._parts * n
1039		return new_path
1040
1041
1042	def __truediv__(self, other: GPathLike) -> GPath:
1043		"""
1044			Alias of `__add__()`.
1045
1046			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1047		"""
1048		return self.__add__(other)
1049
1050
1051	def __and__(self, other: GPathLike) -> Union[GPath, None]:
1052		"""
1053			Equivalent to `self.common_with(other)`, using the default options of `common_with()`.
1054
1055			Usage: <code><var>g1</var> & <var>g2</var></code>
1056		"""
1057		return self.common_with(other)
1058
1059
1060	def __lshift__(self, n: int) -> GPath:
1061		"""
1062			Move the imaginary current working directory `n` steps up the filesystem tree.
1063
1064			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.
1065
1066			If `n` is negative, this is equivalent to `__rshift__(-n)`.
1067
1068			Usage: <code><var>self</var> << <var>n</var></code>
1069
1070			Raises `ValueError` if `self` is an invalid GPath.
1071
1072			Examples
1073			--------
1074			```python
1075			GPath("../SysWOW64/drivers") << 1  # GPath("SysWOW64/drivers")
1076			GPath("../doc") << 2               # GPath("doc")
1077			GPath("/usr/bin") << 2             # GPath("/usr/bin")
1078			```
1079		"""
1080		if n < 0:
1081			return self.__rshift__(-1 * n)
1082		new_path = GPath(self)
1083		if not new_path._root:
1084			new_path._parent_level = max(new_path._parent_level - n, 0)
1085		return new_path
1086
1087
1088	def __rshift__(self, n: int) -> GPath:
1089		"""
1090			Move the imaginary current working directory `n` steps down the filesystem tree.
1091
1092			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.
1093
1094			If `n` is negative, this is equivalent to `__lshift__(-n)`.
1095
1096			Usage: <code><var>self</var> >> <var>n</var></code>
1097
1098			Raises `ValueError` if `self` is an invalid GPath
1099
1100			Examples
1101			--------
1102			```python
1103			GPath("../SysWOW64/drivers") >> 1  # GPath("../../SysWOW64/drivers")
1104			GPath("/usr/bin") >> 2             # GPath("/usr/bin")
1105			```
1106		"""
1107		if n < 0:
1108			return self.__lshift__(-1 * n)
1109		new_path = GPath(self)
1110		if not new_path._root:
1111			new_path._parent_level += n
1112		return new_path
1113
1114
1115	@property
1116	def _tuple(self) -> tuple:
1117		# Get a tuple of all fields
1118		return (
1119			self._root,
1120			self._drive,
1121			self._parent_level,
1122			self._parts,
1123			self._encoding,
1124		)
1125
1126
1127	def _validate(self) -> bool:
1128		# Check if self is in a valid state
1129		if self._parent_level < 0:
1130			raise ValueError(f"invalid GPath, _parent cannot be negative: {repr(self)}")
1131		if self._root:
1132			if self._parent_level != 0:
1133				raise ValueError(f"invalid GPath, _parent must be 0 when root is True: {repr(self)}")
1134		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.

Constructor summary

GPath( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', encoding: Optional[str] = None)

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

Instance variables summary

named_parts: list[str]

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

parent_level: int

Read-only number of levels of parent directories that the path is relative to, which may be 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

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

drive: str

Read-only drive name

absolute: bool

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

root: bool

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

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

Static methods summary

partition( *paths, allow_current: bool = True, allow_parents: bool = True, encoding: Optional[str] = None) -> dict[GPath, list[GPath]]:

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

join(*paths, encoding: Optional[str] = None) -> GPath:

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.

Instance methods summary

as_relative(self, parent_level: Optional[int] = None) -> GPath:

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

as_absolute(self) -> GPath:

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

with_drive(self, drive: Union[str, bytes, NoneType] = None) -> GPath:

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

without_drive(self) -> GPath:

Return a new copy of the path without a drive.

common_with( self, other: Union[GPath, str, bytes, os.PathLike], allow_current: bool = True, allow_parents: bool = False) -> Optional[GPath]:

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

subpath_from( self, base: Union[GPath, str, bytes, os.PathLike]) -> Optional[GPath]:

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

relpath_from( self, origin: Union[GPath, str, bytes, os.PathLike]) -> Optional[GPath]:

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

__hash__(self) -> int:

Calculate hash of the GPath object.

__eq__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:

Check if two GPaths are completely identical.

__bool__(self) -> bool:

Truthy if self is an absolute path, if self is relative to a parent directory, or if self has at least one named component.

__str__(self) -> str:

Return a string representation of the path.

__repr__(self) -> str:

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

__len__(self) -> int:

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

__getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:

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

__iter__(self) -> Iterator[str]:

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

__contains__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:

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

__add__( self, other: Union[GPath, str, bytes, os.PathLike]) -> GPath:

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

__sub__(self, n: int) -> GPath:

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

__mul__(self, n: int) -> GPath:

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

__truediv__( self, other: Union[GPath, str, bytes, os.PathLike]) -> GPath:

Alias of __add__().

__and__( self, other: Union[GPath, str, bytes, os.PathLike]) -> Optional[GPath]:

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

__lshift__(self, n: int) -> GPath:

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

__rshift__(self, n: int) -> GPath:

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

GPath( path: Union[str, bytes, os.PathLike, GPath, NoneType] = '', encoding: Optional[str] = None)
104	def __init__(self, path: Union[str, bytes, os.PathLike, GPath, None]="", encoding: Optional[str]=None):
105		"""
106			Initialise a normalised and generalised abstract file path, possibly by copying an existing GPath object.
107
108			Parameters
109			----------
110			`path`
111			: path-like object representing a (possibly unnormalised) file path, or a GPath object to be copied
112
113			`​encoding`
114			: 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 name should be one of the standard Python text encodings, as listed in the `codecs` module of the standard library. The specified encoding will propagate to new GPaths that result from operations on this GPath. If a binary operation involves two GPaths, the encoding specified by the left operand will be propagated to the result.
115
116			Raises
117			------
118			`ValueError` if `other` is an invalid GPath
119
120			Examples
121			--------
122			```python
123			GPath("/")
124			GPath("/usr/bin")
125			GPath("C:/Program Files")
126			```
127		"""
128
129		self._parts: tuple[str, ...] = tuple()  # root- or parent- relative path
130		self._root: bool = False
131		self._drive: str = ""
132		self._parent_level: int = 0
133
134		self._encoding: Optional[str] = encoding
135
136		if path is None or path == "":
137			return
138
139		if isinstance(path, GPath):
140			path._validate()
141			self._parts = path._parts
142			self._root = path._root
143			self._drive = path._drive
144			self._parent_level = path._parent_level
145
146			self._encoding = path._encoding if encoding is None else encoding
147			return
148
149		path = os.fspath(path)
150
151		if isinstance(path, bytes):
152			if self._encoding is None:
153				path = path.decode(DEFAULT_ENCODING)
154			else:
155				path = path.decode(self._encoding)
156
157		# path is a str
158
159		if len(path) >= 2 and path[1] in _rules.generic_rules.drive_postfixes:
160			self._drive = path[0]
161			driveless_path = path[2:]
162		else:
163			driveless_path = path
164
165		for root in _rules.generic_rules.roots:
166			if driveless_path.startswith(root):
167				self._root = True
168				break
169
170		if self._root:
171			rootless_path = driveless_path[1:]
172		else:
173			rootless_path = driveless_path
174
175
176		parts = _split_relative(rootless_path, delimiters=(set(_rules.generic_rules.separators) | set(_rules.generic_rules.separators)))
177		parts = _normalise_relative(parts)
178		parent_level = 0
179		while parent_level < len(parts) and parts[parent_level] in _rules.generic_rules.parent_indicators:
180			parent_level += 1
181		self._parts = tuple(parts[parent_level:])
182		if self._root == False:
183			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

​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 name should be one of the standard Python text encodings, as listed in the codecs module of the standard library. The specified encoding will propagate to new GPaths that result from operations on this GPath. If a binary operation involves two GPaths, the encoding specified by the left operand will be propagated to the result.

Raises

ValueError if other 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"]
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    # []
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"]
drive: str

Read-only drive name

Examples

GPath("C:/Windows").drive       # "C:"
GPath("/usr/bin").drive         # ""
GPath("../../Documents").drive  # ""
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
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

@staticmethod
def partition( *paths, allow_current: bool = True, allow_parents: bool = True, encoding: Optional[str] = None) -> dict[GPath, list[GPath]]:
310	@staticmethod
311	def partition(*paths, allow_current: bool=True, allow_parents: bool=True, encoding: Optional[str]=None) -> dict[GPath, list[GPath]]:
312		"""
313			Partition a collection of paths based on shared common base paths such that each path belongs to one partition.
314
315			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.
316
317			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.
318
319			Parameters
320			----------
321			`paths: Iterable[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
322			: the paths to be partitioned, which can be given as either a list-like object or as variadic arguments
323
324			`allow_current`
325			: whether non-parent relative paths with no shared components should be considered to have a common base path (see `common_with()`)
326
327			`allow_parents`
328			: 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.
329
330			`​encoding`
331			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
332
333			Returns
334			-------
335			a dictionary that maps the common base path of each partition to a list of relative paths
336
337			Raises
338			------
339			  `ValueError`
340			  if any of the GPaths are invalid
341
342			Examples
343			--------
344			```python
345			GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")
346
347			assert partitions == {
348				GPath("/usr")      : [GPath("bin"), GPath("local")],
349				GPath("../../doc") : [GPath("")],
350				GPath("C:/")       : [GPath("Windows"), GPath("Program Files")],
351			}
352			```
353		"""
354		flattened_paths: list[GPathLike] = []
355		for path_or_list in paths:
356			if _is_gpathlike(path_or_list):
357				flattened_paths.append(path_or_list)
358			else:
359				flattened_paths.extend(path_or_list)
360		gpaths = [path if isinstance(path, GPath) else GPath(path, encoding=encoding) for path in flattened_paths]
361
362		partition_map = {}
363		if len(gpaths) > 0:
364			if allow_parents == True:
365				partition_map[gpaths[0]] = []
366			else:
367				partition_map[gpaths[0]] = [gpaths[0]]
368
369		for path in gpaths[1:]:
370			partition_found = False
371			for partition in partition_map:
372				candidate_common = partition.common_with(path, allow_current=allow_current, allow_parents=allow_parents)
373				if candidate_common is not None:
374					partition_found = True
375					if candidate_common != partition:
376						partition_map[candidate_common] = partition_map[partition]
377						del partition_map[partition]
378					if allow_parents == False:
379						partition_map[candidate_common].append(path)
380					break
381			if not partition_found:
382				if allow_parents == True:
383					partition_map[path] = []
384				else:
385					partition_map[path] = [path]
386
387		for partition, path_list in partition_map.items():
388			partition_map[partition] = [path.subpath_from(partition) for path in path_list]
389
390		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.

​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

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, encoding: Optional[str] = None) -> GPath:
401	@staticmethod
402	def join(*paths, encoding: Optional[str]=None) -> GPath:
403		"""
404			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.
405
406			Parameters
407			----------
408			`paths`: `Sequence[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
409			: the paths to be combined, which can be given as either a list-like object or as variadic arguments
410
411			`​encoding`
412			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
413
414			Returns
415			-------
416			the combined path
417
418			Raises
419			------
420			`ValueError` if any of the GPaths are invalid
421
422			Examples
423			--------
424			```python
425			GPath.join("usr", "local", "bin")          # GPath("usr/local/bin")
426			GPath.join("/usr/local/bin", "../../bin")  # GPath("/usr/bin")
427			GPath.join("C:/", "Windows")               # GPath("C:/Windows")
428			```
429		"""
430		flattened_paths: list[GPathLike] = []
431		for path_or_list in paths:
432			if _is_gpathlike(path_or_list):
433				flattened_paths.append(path_or_list)
434			else:
435				flattened_paths.extend(path_or_list)
436
437		if len(flattened_paths) == 0:
438			return GPath(encoding=encoding)
439
440		combined_path = flattened_paths[0]
441		if not isinstance(combined_path, GPath):
442			combined_path = GPath(combined_path, encoding=encoding)
443		for path in flattened_paths[1:]:
444			combined_path = combined_path + path
445
446		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

​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:
449	def as_relative(self, parent_level: Optional[int]=None) -> GPath:
450		"""
451			Convert the path to a relative path and return a new copy.
452
453			Parameters
454			----------
455			`​parent_level`
456			: 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.
457
458			Raises
459			------
460			`TypeError` if `​parent_level` is not a valid type
461
462			Examples
463			--------
464			```python
465			GPath("/usr/bin").as_relative()      # GPath("usr/bin")
466			GPath("C:/Windows").as_relative()    # GPath("C:Windows")
467			GPath("../Documents").as_relative()  # GPath("../Documents")
468			```
469		"""
470
471		new_path = GPath(self)
472		new_path._root = False
473		if parent_level is None:
474			pass
475		elif isinstance(parent_level, int):
476			new_path._parent_level = parent_level
477		else:
478			raise TypeError(f"parent_level must be an int: {parent_level} ({type(parent_level)})")
479
480		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:
483	def as_absolute(self) -> GPath:
484		"""
485			Convert the path to an absolute path and return a new copy.
486
487			Any parent directory that the path is relative to will be removed. If the path is already absolute, an identical copy is returned.
488
489			Examples
490			--------
491			```python
492			GPath("usr/bin").as_absolute()       # GPath("/usr/bin")
493			GPath("../Documents").as_absolute()  # GPath("/Documents")
494			GPath("C:Windows").as_absolute()     # GPath("C:/Windows")
495			```
496		"""
497		new_path = GPath(self)
498		new_path._root = True
499		new_path._parent_level = 0
500		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:
503	def with_drive(self, drive: Union[str, bytes, None]=None) -> GPath:
504		"""
505			Return a new copy of the path with the drive set to `​drive`.
506
507			If `​drive` is `""` or None, this would be equivalent to `without_drive()`.
508
509			Parameters
510			----------
511			`​drive`
512			: the drive for the returned path, or either `""` or None if the returned path should have no drive
513
514			Returns
515			-------
516			`GPath`
517			: a new path with the given drive
518
519			Raises
520			------
521			- `TypeError` if `​drive` is not a valid type
522			- `ValueError` if `​drive` has more than one character
523
524			Examples
525			--------
526			```python
527			GPath("C:/Windows").with_drive()      # GPath("/Windows")
528			GPath("C:/Windows").with_drive("D")   # GPath("D:/Windows")
529			GPath("/Windows").with_drive("C")     # GPath("C:/Windows")
530			```
531		"""
532		if drive is None:
533			drive = ""
534		elif isinstance(drive, bytes):
535			if self._encoding is None:
536				drive = drive.decode(DEFAULT_ENCODING)
537			else:
538				drive = drive.decode(self._encoding)
539		elif isinstance(drive, str):
540			pass
541		else:
542			raise TypeError(f"drive must be a str or bytes object: {drive} ({type(drive)})")
543
544		if len(drive) > 1:
545			raise ValueError(f"drive can only be a single character, an empty string or None: {drive}")
546
547		new_path = GPath(self)
548		new_path._drive = drive
549		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:
552	def without_drive(self) -> GPath:
553		"""
554			Return a new copy of the path without a drive.
555
556			Equivalent to `with_drive("")` or `with_drive(None)`.
557
558			Returns
559			-------
560			`GPath`
561			: a new path without a drive
562
563			Examples
564			--------
565			```python
566			GPath("C:/Windows").without_drive()      # GPath("/Windows")
567			```
568		"""
569		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]:
572	def common_with(self, other: GPathLike, allow_current: bool=True, allow_parents: bool=False) -> Optional[GPath]:
573		"""
574			Find the longest common base path shared between `self` and `other`, or return None if no such path exists.
575
576			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.
577
578			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>).
579
580			Parameters
581			----------
582			`other`
583			: the path to compare with
584
585			`allow_current`
586			: 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.
587
588			`allow_parents`
589			: 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.
590
591			Returns
592			-------
593			`GPath`
594			: the longest common base path, which may be empty, if it exists
595
596			`None`
597			: otherwise
598
599			Raises
600			------
601			`ValueError` if either `self` or `other` is an invalid GPath
602
603			Examples
604			--------
605			```python
606			GPath("/usr/bin").find_common("/usr/local/bin")               # GPath("/usr")
607			GPath("C:/Windows/System32").find_common("C:/Program Files")  # GPath("C:/")
608			GPath("../Documents").find_common("../Pictures")              # GPath("..")
609			```
610		"""
611		self._validate()
612		if isinstance(other, GPath):
613			other._validate()
614		else:
615			other = GPath(other, encoding=self._encoding)
616
617		if self._drive != other._drive:
618			return None
619		if self._root != other._root:
620			return None
621
622		if allow_parents:
623			allow_current = True
624
625		parts = []
626		if self._root:
627			common_path = GPath(self)
628			for part1, part2 in zip(self._parts, other._parts):
629				if part1 == part2:
630					parts.append(part1)
631		else:
632			if self._parent_level != other._parent_level:
633				if not allow_parents:
634					return None
635
636				common_path = GPath(self)
637				common_path._parent_level = max(self._parent_level, other._parent_level)
638			else:
639				common_path = GPath(self)
640				for part1, part2 in zip(self._parts, other._parts):
641					if part1 == part2:
642						parts.append(part1)
643
644		common_path._parts = tuple(parts)
645
646		if not allow_current and not bool(common_path):
647			if common_path != self or common_path != other:
648				return None
649		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]:
652	def subpath_from(self, base: GPathLike) -> Optional[GPath]:
653		"""
654			Find the relative subpath from `base` to `self` if possible and if `base` contains `self`, or return None otherwise.
655
656			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.
657
658			Similar to `relpath_from()`, but `self` must be a descendent of `base`.
659
660			Parameters
661			----------
662			`base`
663			: the base path that the relative subpath should start from
664
665			Returns
666			-------
667			`GPath`
668			: relative subpath from `base` to `self`, which may be empty, if it exists
669
670			`None`
671			: otherwise
672
673			Raises
674			------
675			`ValueError` if either `self` or `base` is an invalid GPath
676
677			Examples
678			--------
679			```python
680			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
681			GPath("/usr/bin").subpath_from("/usr/local/bin")  # None
682			GPath("/usr/bin").subpath_from("../Documents")    # None
683			```
684		"""
685		if not isinstance(base, GPath):
686			base = GPath(base, encoding=self._encoding)
687
688		if self.common_with(base, allow_current=True, allow_parents=False) is not None and self in base:
689			# 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
690			base_length = len(base._parts)
691			new_path = GPath(self)
692			new_path._parts = self._parts[base_length:]  # () when self == base
693			new_path._drive = ""
694			new_path._root = False
695			new_path._parent_level = 0
696			return new_path
697		else:
698			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]:
701	def relpath_from(self, origin: GPathLike) -> Optional[GPath]:
702		"""
703			Find the relative path from `origin` to `self` if possible, or return None otherwise.
704
705			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.
706
707			Similar to `subpath_from()`, but `self` does not need to be a descendent of `origin`.
708
709			Parameters
710			----------
711			`origin`
712			: the origin that the relative path should start from
713
714			Returns
715			-------
716			`GPath`
717			: relative path from `origin` to `self`, which may be empty, if it exists
718
719			`None`
720			: otherwise
721
722			Raises
723			------
724			`ValueError` if either `self` or `origin` is an invalid GPath
725
726			Examples
727			--------
728			```python
729			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
730			GPath("/usr/bin").subpath_from("/usr/local/bin")  # GPath("../../bin")
731			GPath("/usr/bin").subpath_from("../Documents")    # None
732			```
733		"""
734		self._validate()
735		if not isinstance(origin, GPath):
736			origin = GPath(origin, encoding=self._encoding)
737
738		if origin._root:
739			common = self.common_with(origin)
740			if common is None:
741				return None
742
743			new_path = GPath(self)
744			new_path._parent_level = len(origin) - len(common)
745			new_path._parts = self._parts[len(common):]
746			new_path._drive = ""
747			new_path._root = False
748			return new_path
749
750		else:
751			common = self.common_with(origin, allow_current=True, allow_parents=True)
752			if common is None:
753				return None
754			if common._parent_level > self._parent_level:
755				return None  # Path from common to self's parent cannot be known
756
757			# common._dotdot == self._dotdot
758			# origin._dotdot <= self._dotdot
759
760			new_path = GPath(self)
761			new_path._drive = ""
762			new_path._root = False
763			if len(common) == 0:
764				if origin._parent_level == self._parent_level:
765					new_path._parent_level = len(origin)
766				else:
767					new_path._parent_level = (common._parent_level - origin._parent_level) + len(origin)
768				new_path._parts = self._parts
769			else:
770				new_path._parent_level = len(origin) - len(common)
771				new_path._parts = self._parts[len(common):]
772
773			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 __hash__(self) -> int:
776	def __hash__(self) -> int:
777		"""
778			Calculate hash of the GPath object.
779
780			Usage: <code>hash(<var>g</var>)</code>
781		"""
782		return hash(self._tuple)

Calculate hash of the GPath object.

Usage: hash(g)

def __eq__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:
785	def __eq__(self, other: GPathLike) -> bool:
786		"""
787			Check if two GPaths are completely identical.
788
789			Always return False if `other` is not a GPath object, even if it is a GPath-like object.
790
791			Usage: <code><var>g1</var> == <var>g2</var></code>
792
793			Examples
794			--------
795			```python
796			GPath("/usr/bin") == GPath("/usr/bin")  # True
797			GPath("/usr/bin") == GPath("usr/bin")   # False
798			GPath("C:/") == GPath("D:/")            # False
799			```
800		"""
801		if not isinstance(other, GPath):
802			other = GPath(other, encoding=self._encoding)
803		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:
806	def __bool__(self) -> bool:
807		"""
808			Truthy if `self` is an absolute path, if `self` is relative to a parent directory, or if `self` has at least one named component.
809
810			Usage: <code>bool(<var>g</var>)</code>, <code>not <var>g</var></code>, or <code>if <var>g</var>:</code>
811
812			Examples
813			--------
814			```python
815			bool(GPath("/"))    # True
816			bool(GPath(".."))   # True
817			bool(GPath("doc"))  # True
818			bool(GPath(""))     # False
819			```
820		"""
821		return self._root or self._drive != "" or self._parent_level != 0 or len(self._parts) > 0

Truthy if self is an absolute path, if self is relative to a parent directory, or if self has at least one named component.

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:
824	def __str__(self) -> str:
825		"""
826			Return a string representation of the path.
827
828			Usage: <code>str(<var>g</var>)</code>
829		"""
830		if bool(self):
831			if self.root and self._drive == "":
832				return _rules.generic_rules.roots[0]
833			else:
834				return (self._drive + _rules.generic_rules.drive_postfixes[0] if self._drive != "" else "") + (_rules.generic_rules.roots[0] if self._root else "") + _rules.generic_rules.separators[0].join(self.relative_parts)
835		else:
836			return _rules.generic_rules.current_indicators[0]

Return a string representation of the path.

Usage: str(g)

def __repr__(self) -> str:
839	def __repr__(self) -> str:
840		"""
841			Return a string that, when printed, gives the Python code associated with instantiating the GPath object.
842
843			Usage: <code>repr(<var>g</var>)</code>
844		"""
845		if self._encoding is None:
846			encoding_repr = ""
847		else:
848			encoding_repr = f", encoding={repr(self._encoding)}"
849
850		if bool(self):
851			return f"GPath({repr(str(self))}{encoding_repr})"
852		else:
853			return f"GPath({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:
856	def __len__(self) -> int:
857		"""
858			Get the number of named path components, excluding any drive name or parent directories.
859
860			Usage: <code>len(<var>g</var>)</code>
861
862			Examples
863			--------
864			```python
865			len(GPath("/usr/bin"))    # 2
866			len(GPath("/"))           # 0
867			len(GPath("C:/Windows"))  # 0
868			len(GPath("C:/"))         # 0
869			```
870		"""
871		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]]:
874	def __getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:
875		"""
876			Get a 0-indexed named path component, or a slice of path components, excluding any drive name or parent directories.
877
878			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.
879
880			Examples
881			--------
882			```python
883			GPath("/usr/local/bin")[1]    # "local"
884			GPath("/usr/local/bin")[-1]   # "bin"
885			GPath("/usr/local/bin")[1:]   # ["local", "bin"]
886			GPath("/usr/local/bin")[::2]  # ["usr", "bin"]
887			```
888		"""
889		if isinstance(index, int):
890			return self._parts[index]
891		elif isinstance(index, slice):
892			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]:
895	def __iter__(self) -> Iterator[str]:
896		"""
897			Get an iterator through the named path components, excluding any drive name or parent directories.
898
899			Usage: <code>iter(<var>g</var>)</code> or <code>for <var>p</var> in <var>g</var>:</code>
900		"""
901		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:
904	def __contains__(self, other: GPathLike) -> bool:
905		"""
906			Check if the path represented by `self` contains the path represented by `other`; i.e. check if `self` is a parent directory of `other`.
907
908			Usage: <code><var>other</var> in <var>self</var></code>
909
910			Raises `ValueError` if either GPath is invalid
911
912			Examples
913			--------
914			```python
915			GPath("/usr/local/bin") in GPath("/usr")  # True
916			GPath("/usr/local/bin") in GPath("/bin")  # False
917			GPath("..") in GPath("../..")             # True
918			GPath("..") in GPath("C:/")               # False
919			```
920		"""
921		if not isinstance(other, GPath):
922			other = GPath(other, encoding=self._encoding)
923
924		common_path = self.common_with(other, allow_current=True, allow_parents=True)
925		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:
928	def __add__(self, other: GPathLike) -> GPath:
929		"""
930			Add (concatenate) `other` to the end of `self`, and return a new copy.
931
932			If `other` is an absolute path, the returned path will be an absolute path that matches `other`, apart from the drive name.
933
934			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.
935
936			Alias: `__truediv__()`
937
938			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
939
940			Raises `ValueError` if either GPath is invalid
941
942			Examples
943			--------
944			```python
945			GPath("/usr") + GPath("local/bin")                   # GPath("/usr/local/bin")
946			GPath("C:/Windows/System32") + GPath("../SysWOW64")  # GPath("C:/Windows/SysWOW64")
947			GPath("C:/Windows/System32") + GPath("/usr/bin")     # GPath("C:/usr/bin")
948			GPath("..") + GPath("../..")                         # GPath("../../..")
949			GPath("..") / GPath("../..")                         # GPath("../../..")
950			```
951		"""
952		if isinstance(other, GPath):
953			other._validate
954		else:
955			other = GPath(other, encoding=self._encoding)
956
957		new_path = GPath(self)
958		if other._root:
959			new_path._parts = other._parts
960			new_path._root = other._root
961			new_path._parent_level = other._parent_level
962		else:
963			new_parts = [part for part in self._parts]
964			for i in range(other._parent_level):
965				if len(new_parts) > 0:
966					new_parts.pop()
967				elif not new_path._root:
968					new_path._parent_level += 1
969				else:
970					pass  # parent of directory of root is still root
971
972			new_parts.extend(other._parts)
973			new_path._parts = tuple(new_parts)
974
975		if other._drive != "":
976			new_path._drive = other._drive
977
978		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:
 981	def __sub__(self, n: int) -> GPath:
 982		"""
 983			Remove `n` components from the end of the path and return a new copy.
 984
 985			Usage: <code><var>self</var> - <var>n</var></code>
 986
 987			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative
 988
 989			Examples
 990			--------
 991			```python
 992			GPath("C:/Windows/System32") - 1  # GPath("C:/Windows")
 993			GPath("/usr/bin") - 2             # GPath("/")
 994			GPath("Documents") - 3            # GPath("..")
 995			GPath("/") - 1                    # GPath("/")
 996			```
 997		"""
 998		if n < 0:
 999			raise ValueError("cannot subtract a negative number of components from the path: {n}; use __add__() instead")
1000
1001		new_path = GPath(self)
1002		new_parts = [part for part in self._parts]
1003		for i in range(n):
1004			if len(new_parts) > 0:
1005				new_parts.pop()
1006			elif not new_path._root:
1007				new_path._parent_level += 1
1008			else:
1009				pass  # removing components from root should still give root
1010		new_path._parts = tuple(new_parts)
1011		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:
1014	def __mul__(self, n: int) -> GPath:
1015		"""
1016			Duplicate the named components of `self` `n` times and return a new path with the duplicated components.
1017
1018			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.
1019
1020			If `n` is 0, the result is an empty path (either relative or absolute).
1021
1022			Usage: <code><var>self</var> * <var>n</var></code>
1023
1024			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative.
1025
1026			Examples
1027			--------
1028			```python
1029			GPath("/usr/bin") * 2    # GPath("/usr/bin/usr/bin")
1030			GPath("../docs") * 2     # GPath("../../docs/docs")
1031			GPath("C:/Windows") * 0  # GPath("C:/")
1032			```
1033		"""
1034		if n < 0:
1035			raise ValueError("cannot multiply path by a negative integer: {n}")
1036		new_path = GPath(self)
1037		new_path._parent_level = self._parent_level * n
1038		new_path._parts = self._parts * n
1039		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:
1042	def __truediv__(self, other: GPathLike) -> GPath:
1043		"""
1044			Alias of `__add__()`.
1045
1046			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1047		"""
1048		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]:
1051	def __and__(self, other: GPathLike) -> Union[GPath, None]:
1052		"""
1053			Equivalent to `self.common_with(other)`, using the default options of `common_with()`.
1054
1055			Usage: <code><var>g1</var> & <var>g2</var></code>
1056		"""
1057		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:
1060	def __lshift__(self, n: int) -> GPath:
1061		"""
1062			Move the imaginary current working directory `n` steps up the filesystem tree.
1063
1064			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.
1065
1066			If `n` is negative, this is equivalent to `__rshift__(-n)`.
1067
1068			Usage: <code><var>self</var> << <var>n</var></code>
1069
1070			Raises `ValueError` if `self` is an invalid GPath.
1071
1072			Examples
1073			--------
1074			```python
1075			GPath("../SysWOW64/drivers") << 1  # GPath("SysWOW64/drivers")
1076			GPath("../doc") << 2               # GPath("doc")
1077			GPath("/usr/bin") << 2             # GPath("/usr/bin")
1078			```
1079		"""
1080		if n < 0:
1081			return self.__rshift__(-1 * n)
1082		new_path = GPath(self)
1083		if not new_path._root:
1084			new_path._parent_level = max(new_path._parent_level - n, 0)
1085		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:
1088	def __rshift__(self, n: int) -> GPath:
1089		"""
1090			Move the imaginary current working directory `n` steps down the filesystem tree.
1091
1092			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.
1093
1094			If `n` is negative, this is equivalent to `__lshift__(-n)`.
1095
1096			Usage: <code><var>self</var> >> <var>n</var></code>
1097
1098			Raises `ValueError` if `self` is an invalid GPath
1099
1100			Examples
1101			--------
1102			```python
1103			GPath("../SysWOW64/drivers") >> 1  # GPath("../../SysWOW64/drivers")
1104			GPath("/usr/bin") >> 2             # GPath("/usr/bin")
1105			```
1106		"""
1107		if n < 0:
1108			return self.__lshift__(-1 * n)
1109		new_path = GPath(self)
1110		if not new_path._root:
1111			new_path._parent_level += n
1112		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]