Edit on GitHub

gpath

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

relative_parts: list[str]

Read-only relative components of the path, not including the filesystem root or device name, with a copy of parent_indicator for each level of parent directory

drive: str

Read-only device 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

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 device 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 device name or parent directories.

__iter__(self) -> Iterator[str]:

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

Examples

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

@staticmethod
def partition( *paths, allow_current: bool = True, allow_parents: bool = True, encoding: Optional[str] = None) -> dict[GPath, list[GPath]]:
309	@staticmethod
310	def partition(*paths, allow_current: bool=True, allow_parents: bool=True, encoding: Optional[str]=None) -> dict[GPath, list[GPath]]:
311		"""
312			Partition a collection of paths based on shared common base paths such that each path belongs to one partition.
313
314			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.
315
316			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.
317
318			Parameters
319			----------
320			`paths: Iterable[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
321			: the paths to be partitioned, which can be given as either a list-like object or as variadic arguments
322
323			`allow_current`
324			: whether non-parent relative paths with no shared components should be considered to have a common base path (see `common_with()`)
325
326			`allow_parents`
327			: 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.
328
329			`​encoding`
330			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
331
332			Returns
333			-------
334			a dictionary that maps the common base path of each partition to a list of relative paths
335
336			Raises
337			------
338			  `ValueError`
339			  if any of the GPaths are invalid
340
341			Examples
342			--------
343			```python
344			GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")
345
346			assert partitions == {
347				GPath("/usr")      : [GPath("bin"), GPath("local")],
348				GPath("../../doc") : [GPath("")],
349				GPath("C:/")       : [GPath("Windows"), GPath("Program Files")],
350			}
351			```
352		"""
353		flattened_paths: list[GPathLike] = []
354		for path_or_list in paths:
355			if _is_gpathlike(path_or_list):
356				flattened_paths.append(path_or_list)
357			else:
358				flattened_paths.extend(path_or_list)
359		gpaths = [path if isinstance(path, GPath) else GPath(path, encoding=encoding) for path in flattened_paths]
360
361		partition_map = {}
362		if len(gpaths) > 0:
363			if allow_parents == True:
364				partition_map[gpaths[0]] = []
365			else:
366				partition_map[gpaths[0]] = [gpaths[0]]
367
368		for path in gpaths[1:]:
369			partition_found = False
370			for partition in partition_map:
371				candidate_common = partition.common_with(path, allow_current=allow_current, allow_parents=allow_parents)
372				if candidate_common is not None:
373					partition_found = True
374					if candidate_common != partition:
375						partition_map[candidate_common] = partition_map[partition]
376						del partition_map[partition]
377					if allow_parents == False:
378						partition_map[candidate_common].append(path)
379					break
380			if not partition_found:
381				if allow_parents == True:
382					partition_map[path] = []
383				else:
384					partition_map[path] = [path]
385
386		for partition, path_list in partition_map.items():
387			partition_map[partition] = [path.subpath_from(partition) for path in path_list]
388
389		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:
398	@staticmethod
399	def join(*paths, encoding: Optional[str]=None) -> GPath:
400		"""
401			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.
402
403			Parameters
404			----------
405			`paths`: `Sequence[GPath | str | bytes | os.PathLike]` or `*paths: GPath | str | bytes | os.PathLike`
406			: the paths to be combined, which can be given as either a list-like object or as variadic arguments
407
408			`​encoding`
409			: the text encoding that should be used to decode bytes-like objects in `paths`, if any (see `__init__()`).
410
411			Returns
412			-------
413			the combined path
414
415			Raises
416			------
417			`ValueError` if any of the GPaths are invalid
418
419			Examples
420			--------
421			```python
422			GPath.join("usr", "local", "bin")          # GPath("usr/local/bin")
423			GPath.join("/usr/local/bin", "../../bin")  # GPath("/usr/bin")
424			GPath.join("C:/", "Windows")               # GPath("C:/Windows")
425			```
426		"""
427		flattened_paths: list[GPathLike] = []
428		for path_or_list in paths:
429			if _is_gpathlike(path_or_list):
430				flattened_paths.append(path_or_list)
431			else:
432				flattened_paths.extend(path_or_list)
433
434		if len(flattened_paths) == 0:
435			return GPath(encoding=encoding)
436
437		combined_path = flattened_paths[0]
438		if not isinstance(combined_path, GPath):
439			combined_path = GPath(combined_path, encoding=encoding)
440		for path in flattened_paths[1:]:
441			combined_path = combined_path + path
442
443		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:
446	def as_relative(self, parent_level: Optional[int]=None) -> GPath:
447		"""
448			Convert the path to a relative path and return a new copy.
449
450			Parameters
451			----------
452			`​parent_level`
453			: 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.
454
455			Raises
456			------
457			`TypeError` if `​parent_level` is not a valid type
458
459			Examples
460			--------
461			```python
462			GPath("/usr/bin").as_relative()      # GPath("usr/bin")
463			GPath("C:/Windows").as_relative()    # GPath("C:Windows")
464			GPath("../Documents").as_relative()  # GPath("../Documents")
465			```
466		"""
467
468		new_path = GPath(self)
469		new_path._root = False
470		if parent_level is None:
471			pass
472		elif isinstance(parent_level, int):
473			new_path._parent_level = parent_level
474		else:
475			raise TypeError(f"parent_level must be an int: {parent_level} ({type(parent_level)})")
476
477		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:
480	def as_absolute(self) -> GPath:
481		"""
482			Convert the path to an absolute path and return a new copy.
483
484			Any parent directory that the path is relative to will be removed. If the path is already absolute, an identical copy is returned.
485
486			Examples
487			--------
488			```python
489			GPath("usr/bin").as_absolute()       # GPath("/usr/bin")
490			GPath("../Documents").as_absolute()  # GPath("/Documents")
491			GPath("C:Windows").as_absolute()     # GPath("C:/Windows")
492			```
493		"""
494		new_path = GPath(self)
495		new_path._root = True
496		new_path._parent_level = 0
497		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:
500	def with_drive(self, drive: Union[str, bytes, None]=None) -> GPath:
501		"""
502			Return a new copy of the path with the drive set to `​drive`.
503
504			If `​drive` is `""` or None, this would be equivalent to `without_drive()`.
505
506			Parameters
507			----------
508			`​drive`
509			: the drive for the returned path, or either `""` or None if the returned path should have no drive
510
511			Returns
512			-------
513			`GPath`
514			: a new path with the given drive
515
516			Raises
517			------
518			- `TypeError` if `​drive` is not a valid type
519			- `ValueError` if `​drive` has more than one character
520
521			Examples
522			--------
523			```python
524			GPath("C:/Windows").with_drive()      # GPath("/Windows")
525			GPath("C:/Windows").with_drive("D")   # GPath("D:/Windows")
526			GPath("/Windows").with_drive("C")     # GPath("C:/Windows")
527			```
528		"""
529		if drive is None:
530			drive = ""
531		elif isinstance(drive, bytes):
532			if self._encoding is None:
533				drive = drive.decode(DEFAULT_ENCODING)
534			else:
535				drive = drive.decode(self._encoding)
536		elif isinstance(drive, str):
537			pass
538		else:
539			raise TypeError(f"drive must be a str or bytes object: {drive} ({type(drive)})")
540
541		if len(drive) > 1:
542			raise ValueError(f"drive can only be a single character, an empty string or None: {drive}")
543
544		new_path = GPath(self)
545		new_path._drive = drive
546		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:
549	def without_drive(self) -> GPath:
550		"""
551			Return a new copy of the path without a drive.
552
553			Equivalent to `with_drive("")` or `with_drive(None)`.
554
555			Returns
556			-------
557			`GPath`
558			: a new path without a drive
559
560			Examples
561			--------
562			```python
563			GPath("C:/Windows").without_drive()      # GPath("/Windows")
564			```
565		"""
566		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]:
569	def common_with(self, other: GPathLike, allow_current: bool=True, allow_parents: bool=False) -> Optional[GPath]:
570		"""
571			Find the longest common base path shared between `self` and `other`, or return None if no such path exists.
572
573			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 device names), or in other cases as controlled by the `allow_current` and `allow_parents` options.
574
575			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>).
576
577			Parameters
578			----------
579			`other`
580			: the path to compare with
581
582			`allow_current`
583			: 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.
584
585			`allow_parents`
586			: 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.
587
588			Returns
589			-------
590			`GPath`
591			: the longest common base path, which may be empty, if it exists
592
593			`None`
594			: otherwise
595
596			Raises
597			------
598			`ValueError` if either `self` or `other` is an invalid GPath
599
600			Examples
601			--------
602			```python
603			GPath("/usr/bin").find_common("/usr/local/bin")               # GPath("/usr")
604			GPath("C:/Windows/System32").find_common("C:/Program Files")  # GPath("C:/")
605			GPath("../Documents").find_common("../Pictures")              # GPath("..")
606			```
607		"""
608		self._validate()
609		if isinstance(other, GPath):
610			other._validate()
611		else:
612			other = GPath(other, encoding=self._encoding)
613
614		if self._drive != other._drive:
615			return None
616		if self._root != other._root:
617			return None
618
619		if allow_parents:
620			allow_current = True
621
622		parts = []
623		if self._root:
624			common_path = GPath(self)
625			for part1, part2 in zip(self._parts, other._parts):
626				if part1 == part2:
627					parts.append(part1)
628		else:
629			if self._parent_level != other._parent_level:
630				if not allow_parents:
631					return None
632
633				common_path = GPath(self)
634				common_path._parent_level = max(self._parent_level, other._parent_level)
635			else:
636				common_path = GPath(self)
637				for part1, part2 in zip(self._parts, other._parts):
638					if part1 == part2:
639						parts.append(part1)
640
641		common_path._parts = tuple(parts)
642
643		if not allow_current and not bool(common_path):
644			if common_path != self or common_path != other:
645				return None
646		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 device 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]:
649	def subpath_from(self, base: GPathLike) -> Optional[GPath]:
650		"""
651			Find the relative subpath from `base` to `self` if possible and if `base` contains `self`, or return None otherwise.
652
653			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.
654
655			Similar to `relpath_from()`, but `self` must be a descendent of `base`.
656
657			Parameters
658			----------
659			`base`
660			: the base path that the relative subpath should start from
661
662			Returns
663			-------
664			`GPath`
665			: relative subpath from `base` to `self`, which may be empty, if it exists
666
667			`None`
668			: otherwise
669
670			Raises
671			------
672			`ValueError` if either `self` or `base` is an invalid GPath
673
674			Examples
675			--------
676			```python
677			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
678			GPath("/usr/bin").subpath_from("/usr/local/bin")  # None
679			GPath("/usr/bin").subpath_from("../Documents")    # None
680			```
681		"""
682		if not isinstance(base, GPath):
683			base = GPath(base, encoding=self._encoding)
684
685		if self.common_with(base, allow_current=True, allow_parents=False) is not None and self in base:
686			# 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
687			base_length = len(base._parts)
688			new_path = GPath(self)
689			new_path._parts = self._parts[base_length:]  # () when self == base
690			new_path._drive = ""
691			new_path._root = False
692			new_path._parent_level = 0
693			return new_path
694		else:
695			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]:
698	def relpath_from(self, origin: GPathLike) -> Optional[GPath]:
699		"""
700			Find the relative path from `origin` to `self` if possible, or return None otherwise.
701
702			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.
703
704			Similar to `subpath_from()`, but `self` does not need to be a descendent of `origin`.
705
706			Parameters
707			----------
708			`origin`
709			: the origin that the relative path should start from
710
711			Returns
712			-------
713			`GPath`
714			: relative path from `origin` to `self`, which may be empty, if it exists
715
716			`None`
717			: otherwise
718
719			Raises
720			------
721			`ValueError` if either `self` or `origin` is an invalid GPath
722
723			Examples
724			--------
725			```python
726			GPath("/usr/local/bin").subpath_from("/usr")      # GPath("local/bin")
727			GPath("/usr/bin").subpath_from("/usr/local/bin")  # GPath("../../bin")
728			GPath("/usr/bin").subpath_from("../Documents")    # None
729			```
730		"""
731		self._validate()
732		if not isinstance(origin, GPath):
733			origin = GPath(origin, encoding=self._encoding)
734
735		if origin._root:
736			common = self.common_with(origin)
737			if common is None:
738				return None
739
740			new_path = GPath(self)
741			new_path._parent_level = len(origin) - len(common)
742			new_path._parts = self._parts[len(common):]
743			new_path._drive = ""
744			new_path._root = False
745			return new_path
746
747		else:
748			common = self.common_with(origin, allow_current=True, allow_parents=True)
749			if common is None:
750				return None
751			if common._parent_level > self._parent_level:
752				return None  # Path from common to self's parent cannot be known
753
754			# common._dotdot == self._dotdot
755			# origin._dotdot <= self._dotdot
756
757			new_path = GPath(self)
758			new_path._drive = ""
759			new_path._root = False
760			if len(common) == 0:
761				if origin._parent_level == self._parent_level:
762					new_path._parent_level = len(origin)
763				else:
764					new_path._parent_level = (common._parent_level - origin._parent_level) + len(origin)
765				new_path._parts = self._parts
766			else:
767				new_path._parent_level = len(origin) - len(common)
768				new_path._parts = self._parts[len(common):]
769
770			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:
773	def __hash__(self) -> int:
774		"""
775			Calculate hash of the GPath object.
776
777			Usage: <code>hash(<var>g</var>)</code>
778		"""
779		return hash(self._tuple)

Calculate hash of the GPath object.

Usage: hash(g)

def __eq__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:
782	def __eq__(self, other: GPathLike) -> bool:
783		"""
784			Check if two GPaths are completely identical.
785
786			Always return False if `other` is not a GPath object, even if it is a GPath-like object.
787
788			Usage: <code><var>g1</var> == <var>g2</var></code>
789
790			Examples
791			--------
792			```python
793			GPath("/usr/bin") == GPath("/usr/bin")  # True
794			GPath("/usr/bin") == GPath("usr/bin")   # False
795			GPath("C:/") == GPath("D:/")            # False
796			```
797		"""
798		if not isinstance(other, GPath):
799			other = GPath(other, encoding=self._encoding)
800		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:
803	def __bool__(self) -> bool:
804		"""
805			Truthy if `self` is an absolute path, if `self` is relative to a parent directory, or if `self` has at least one named component.
806
807			Usage: <code>bool(<var>g</var>)</code>, <code>not <var>g</var></code>, or <code>if <var>g</var>:</code>
808
809			Examples
810			--------
811			```python
812			bool(GPath("/"))    # True
813			bool(GPath(".."))   # True
814			bool(GPath("doc"))  # True
815			bool(GPath(""))     # False
816			```
817		"""
818		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:
821	def __str__(self) -> str:
822		"""
823			Return a string representation of the path.
824
825			Usage: <code>str(<var>g</var>)</code>
826		"""
827		if bool(self):
828			if self.root and self._drive == "":
829				return _rules.generic_rules.roots[0]
830			else:
831				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)
832		else:
833			return _rules.generic_rules.current_indicators[0]

Return a string representation of the path.

Usage: str(g)

def __repr__(self) -> str:
836	def __repr__(self) -> str:
837		"""
838			Return a string that, when printed, gives the Python code associated with instantiating the GPath object.
839
840			Usage: <code>repr(<var>g</var>)</code>
841		"""
842		if self._encoding is None:
843			encoding_repr = ""
844		else:
845			encoding_repr = f", encoding={repr(self._encoding)}"
846
847		if bool(self):
848			return f"GPath({repr(str(self))}{encoding_repr})"
849		else:
850			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:
853	def __len__(self) -> int:
854		"""
855			Get the number of named path components, excluding any device name or parent directories.
856
857			Usage: <code>len(<var>g</var>)</code>
858
859			Examples
860			--------
861			```python
862			len(GPath("/usr/bin"))    # 2
863			len(GPath("/"))           # 0
864			len(GPath("C:/Windows"))  # 0
865			len(GPath("C:/"))         # 0
866			```
867		"""
868		return len(self._parts)

Get the number of named path components, excluding any device 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]]:
871	def __getitem__(self, index: Union[int, slice]) -> Union[str, list[str]]:
872		"""
873			Get a 0-indexed named path component, or a slice of path components, excluding any device name or parent directories.
874
875			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.
876
877			Examples
878			--------
879			```python
880			GPath("/usr/local/bin")[1]    # "local"
881			GPath("/usr/local/bin")[-1]   # "bin"
882			GPath("/usr/local/bin")[1:]   # ["local", "bin"]
883			GPath("/usr/local/bin")[::2]  # ["usr", "bin"]
884			```
885		"""
886		if isinstance(index, int):
887			return self._parts[index]
888		elif isinstance(index, slice):
889			return list(self._parts[index])

Get a 0-indexed named path component, or a slice of path components, excluding any device 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]:
892	def __iter__(self) -> Iterator[str]:
893		"""
894			Get an iterator through the named path components, excluding any device name or parent directories.
895
896			Usage: <code>iter(<var>g</var>)</code> or <code>for <var>p</var> in <var>g</var>:</code>
897		"""
898		return iter(self._parts)

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

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

def __contains__(self, other: Union[GPath, str, bytes, os.PathLike]) -> bool:
901	def __contains__(self, other: GPathLike) -> bool:
902		"""
903			Check if the path represented by `self` contains the path represented by `other`; i.e. check if `self` is a parent directory of `other`.
904
905			Usage: <code><var>other</var> in <var>self</var></code>
906
907			Raises `ValueError` if either GPath is invalid
908
909			Examples
910			--------
911			```python
912			GPath("/usr/local/bin") in GPath("/usr")  # True
913			GPath("/usr/local/bin") in GPath("/bin")  # False
914			GPath("..") in GPath("../..")             # True
915			GPath("..") in GPath("C:/")               # False
916			```
917		"""
918		if not isinstance(other, GPath):
919			other = GPath(other, encoding=self._encoding)
920
921		common_path = self.common_with(other, allow_current=True, allow_parents=True)
922		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:
925	def __add__(self, other: GPathLike) -> GPath:
926		"""
927			Add (concatenate) `other` to the end of `self`, and return a new copy.
928
929			If `other` is an absolute path, the returned path will be an absolute path that matches `other`, apart from the device name.
930
931			If `other` has a device name, the returned path will have the same device name as `other`. Otherwise, the returned path will have the same device name as `self`. If neither has a device name, the returned path will not have a device name as well.
932
933			Alias: `__truediv__()`
934
935			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
936
937			Raises `ValueError` if either GPath is invalid
938
939			Examples
940			--------
941			```python
942			GPath("/usr") + GPath("local/bin")                   # GPath("/usr/local/bin")
943			GPath("C:/Windows/System32") + GPath("../SysWOW64")  # GPath("C:/Windows/SysWOW64")
944			GPath("C:/Windows/System32") + GPath("/usr/bin")     # GPath("C:/usr/bin")
945			GPath("..") + GPath("../..")                         # GPath("../../..")
946			GPath("..") / GPath("../..")                         # GPath("../../..")
947			```
948		"""
949		if isinstance(other, GPath):
950			other._validate
951		else:
952			other = GPath(other, encoding=self._encoding)
953
954		new_path = GPath(self)
955		if other._root:
956			new_path._parts = other._parts
957			new_path._root = other._root
958			new_path._parent_level = other._parent_level
959		else:
960			new_parts = [part for part in self._parts]
961			for i in range(other._parent_level):
962				if len(new_parts) > 0:
963					new_parts.pop()
964				elif not new_path._root:
965					new_path._parent_level += 1
966				else:
967					pass  # parent of directory of root is still root
968
969			new_parts.extend(other._parts)
970			new_path._parts = tuple(new_parts)
971
972		if other._drive != "":
973			new_path._drive = other._drive
974
975		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 device name.

If other has a device name, the returned path will have the same device name as other. Otherwise, the returned path will have the same device name as self. If neither has a device name, the returned path will not have a device name 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:
 978	def __sub__(self, n: int) -> GPath:
 979		"""
 980			Remove `n` components from the end of the path and return a new copy.
 981
 982			Usage: <code><var>self</var> - <var>n</var></code>
 983
 984			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative
 985
 986			Examples
 987			--------
 988			```python
 989			GPath("C:/Windows/System32") - 1  # GPath("C:/Windows")
 990			GPath("/usr/bin") - 2             # GPath("/")
 991			GPath("Documents") - 3            # GPath("..")
 992			GPath("/") - 1                    # GPath("/")
 993			```
 994		"""
 995		if n < 0:
 996			raise ValueError("cannot subtract a negative number of components from the path: {n}; use __add__() instead")
 997
 998		new_path = GPath(self)
 999		new_parts = [part for part in self._parts]
1000		for i in range(n):
1001			if len(new_parts) > 0:
1002				new_parts.pop()
1003			elif not new_path._root:
1004				new_path._parent_level += 1
1005			else:
1006				pass  # removing components from root should still give root
1007		new_path._parts = tuple(new_parts)
1008		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:
1011	def __mul__(self, n: int) -> GPath:
1012		"""
1013			Duplicate the named components of `self` `n` times and return a new path with the duplicated components.
1014
1015			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.
1016
1017			If `n` is 0, the result is an empty path (either relative or absolute).
1018
1019			Usage: <code><var>self</var> * <var>n</var></code>
1020
1021			Raises `ValueError` if `self` is an invalid GPath or if `n` is negative.
1022
1023			Examples
1024			--------
1025			```python
1026			GPath("/usr/bin") * 2    # GPath("/usr/bin/usr/bin")
1027			GPath("../docs") * 2     # GPath("../../docs/docs")
1028			GPath("C:/Windows") * 0  # GPath("C:/")
1029			```
1030		"""
1031		if n < 0:
1032			raise ValueError("cannot multiply path by a negative integer: {n}")
1033		new_path = GPath(self)
1034		new_path._parent_level = self._parent_level * n
1035		new_path._parts = self._parts * n
1036		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:
1039	def __truediv__(self, other: GPathLike) -> GPath:
1040		"""
1041			Alias of `__add__()`.
1042
1043			Usage: <code><var>self</var> + <var>other</var></code> or <code><var>self</var> / <var>other</var></code>
1044		"""
1045		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]:
1048	def __and__(self, other: GPathLike) -> Union[GPath, None]:
1049		"""
1050			Equivalent to `self.common_with(other)`, using the default options of `common_with()`.
1051
1052			Usage: <code><var>g1</var> & <var>g2</var></code>
1053		"""
1054		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:
1057	def __lshift__(self, n: int) -> GPath:
1058		"""
1059			Move the imaginary current working directory `n` steps up the filesystem tree.
1060
1061			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.
1062
1063			If `n` is negative, this is equivalent to `__rshift__(-n)`.
1064
1065			Usage: <code><var>self</var> << <var>n</var></code>
1066
1067			Raises `ValueError` if `self` is an invalid GPath.
1068
1069			Examples
1070			--------
1071			```python
1072			GPath("../SysWOW64/drivers") << 1  # GPath("SysWOW64/drivers")
1073			GPath("../doc") << 2               # GPath("doc")
1074			GPath("/usr/bin") << 2             # GPath("/usr/bin")
1075			```
1076		"""
1077		if n < 0:
1078			return self.__rshift__(-1 * n)
1079		new_path = GPath(self)
1080		if not new_path._root:
1081			new_path._parent_level = max(new_path._parent_level - n, 0)
1082		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:
1085	def __rshift__(self, n: int) -> GPath:
1086		"""
1087			Move the imaginary current working directory `n` steps down the filesystem tree.
1088
1089			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.
1090
1091			If `n` is negative, this is equivalent to `__lshift__(-n)`.
1092
1093			Usage: <code><var>self</var> >> <var>n</var></code>
1094
1095			Raises `ValueError` if `self` is an invalid GPath
1096
1097			Examples
1098			--------
1099			```python
1100			GPath("../SysWOW64/drivers") >> 1  # GPath("../../SysWOW64/drivers")
1101			GPath("/usr/bin") >> 2             # GPath("/usr/bin")
1102			```
1103		"""
1104		if n < 0:
1105			return self.__lshift__(-1 * n)
1106		new_path = GPath(self)
1107		if not new_path._root:
1108			new_path._parent_level += n
1109		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]