Pathlib-style classes for cloud storage services that provide seamless access to AWS S3, Google Cloud Storage, and Azure Blob Storage with familiar filesystem operations.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Essential pathlib-compatible operations for working with cloud storage paths. These operations provide the foundation for path construction, manipulation, and basic filesystem interactions that work consistently across all supported cloud providers.
Create and manipulate cloud paths using familiar pathlib syntax.
class CloudPath:
def __init__(self, cloud_path: str, *parts: str, client=None):
"""
Create a new CloudPath instance.
Args:
cloud_path: Cloud storage URI (e.g., "s3://bucket/path")
*parts: Additional path segments to join
client: Optional client instance for cloud operations
"""
@classmethod
def from_uri(cls, uri: str) -> "CloudPath":
"""Create CloudPath instance from URI string."""
@classmethod
def is_valid_cloudpath(cls, path: str, raise_on_error: bool = False) -> bool:
"""
Validate if path is a valid cloud path.
Args:
path: Path string to validate
raise_on_error: Raise exception on invalid path
Returns:
True if valid cloud path
"""Access path components and metadata using pathlib-style properties.
@property
def name(self) -> str:
"""Final path component (filename)."""
@property
def stem(self) -> str:
"""Final path component without suffix."""
@property
def suffix(self) -> str:
"""File extension including the dot."""
@property
def suffixes(self) -> list[str]:
"""List of all file extensions."""
@property
def parent(self) -> "CloudPath":
"""Parent directory path."""
@property
def parents(self) -> "CloudPath.parents":
"""Sequence of parent paths."""
@property
def parts(self) -> tuple[str, ...]:
"""Tuple of path components."""
@property
def anchor(self) -> str:
"""Cloud prefix (e.g., "s3://")."""
@property
def drive(self) -> str:
"""Drive name (bucket/container name)."""Modify and combine paths using standard pathlib operations.
def __truediv__(self, other: str) -> "CloudPath":
"""Join paths using / operator."""
def joinpath(self, *pathsegments: str) -> "CloudPath":
"""
Join path segments.
Args:
*pathsegments: Path segments to join
Returns:
New CloudPath with joined segments
"""
def with_name(self, name: str) -> "CloudPath":
"""
Return new path with different filename.
Args:
name: New filename
Returns:
New CloudPath with replaced filename
"""
def with_suffix(self, suffix: str) -> "CloudPath":
"""
Return new path with different suffix.
Args:
suffix: New file extension (including dot)
Returns:
New CloudPath with replaced suffix
"""
def with_stem(self, stem: str) -> "CloudPath":
"""
Return new path with different stem.
Args:
stem: New filename without extension
Returns:
New CloudPath with replaced stem
"""
def with_segments(self, *pathsegments: str) -> "CloudPath":
"""
Create new path from segments.
Args:
*pathsegments: Path segments for new path
Returns:
New CloudPath constructed from segments
"""Resolve and normalize paths (note: most operations are no-ops for cloud paths).
def absolute(self) -> "CloudPath":
"""Return absolute path (no-op for cloud paths)."""
def resolve(self, strict: bool = False) -> "CloudPath":
"""Resolve path (no-op for cloud paths)."""
def relative_to(self, other: typing.Union[str, "CloudPath"]) -> "CloudPath":
"""
Return relative path from other path.
Args:
other: Base path for relative calculation
Returns:
Relative path from other to self
"""
def is_relative_to(self, other: typing.Union[str, "CloudPath"]) -> bool:
"""
Check if path is relative to other path.
Args:
other: Base path to check against
Returns:
True if path is under other path
"""Validate and check path properties.
@classmethod
def validate(cls, v):
"""Pydantic validator for CloudPath instances."""
def __str__(self) -> str:
"""String representation of the path."""
def __repr__(self) -> str:
"""Detailed string representation."""
def __hash__(self) -> int:
"""Hash value for use in sets and dicts."""
def __eq__(self, other) -> bool:
"""Equality comparison."""
def __lt__(self, other) -> bool:
"""Less than comparison for sorting."""
def __fspath__(self) -> str:
"""
Return path for os.fspath() compatibility.
Returns local cached path if available.
"""from cloudpathlib import CloudPath
# Create path
path = CloudPath("s3://my-bucket/data/file.txt")
# Access components
print(path.name) # "file.txt"
print(path.stem) # "file"
print(path.suffix) # ".txt"
print(path.parent) # S3Path('s3://my-bucket/data/')
print(path.parts) # ('s3://my-bucket', 'data', 'file.txt')
# Path manipulation
new_path = path.with_suffix('.json') # s3://my-bucket/data/file.json
parent_dir = path.parent # s3://my-bucket/data/
sibling = path.parent / "other.txt" # s3://my-bucket/data/other.txt# Multiple ways to construct paths
path1 = CloudPath("s3://bucket", "folder", "file.txt")
path2 = CloudPath("s3://bucket") / "folder" / "file.txt"
path3 = CloudPath("s3://bucket").joinpath("folder", "file.txt")
# All result in: S3Path('s3://bucket/folder/file.txt')
assert path1 == path2 == path3# Check if string is valid cloud path
CloudPath.is_valid_cloudpath("s3://bucket/file.txt") # True
CloudPath.is_valid_cloudpath("/local/path") # False
CloudPath.is_valid_cloudpath("not-a-path") # False
# Validation with error handling
try:
CloudPath.is_valid_cloudpath("invalid://path", raise_on_error=True)
except InvalidPrefixError:
print("Invalid cloud path prefix")path = CloudPath("s3://bucket/level1/level2/level3/file.txt")
# Navigate up the hierarchy
print(path.parent) # s3://bucket/level1/level2/level3/
print(path.parent.parent) # s3://bucket/level1/level2/
print(list(path.parents)) # All parent paths
# Check relationships
base = CloudPath("s3://bucket/level1")
print(path.is_relative_to(base)) # True
print(path.relative_to(base)) # level2/level3/file.txtInstall with Tessl CLI
npx tessl i tessl/pypi-cloudpathlib