Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ instance/

# Sphinx documentation
docs/_build/
docs/changelog.md

# PyBuilder
.pybuilder/
Expand Down Expand Up @@ -143,3 +144,6 @@ upath/_version.py

# vscode workspace settings
.vscode/

# mac
**/.DS_Store
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ repos:
args: ['--assume-in-merge']
- id: check-toml
- id: check-yaml
exclude: ^mkdocs\.yml$
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
Expand Down
24 changes: 24 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version, and other tools you might need
build:
os: ubuntu-24.04
tools:
python: "3.13"
jobs:
pre_create_environment:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
create_environment:
- uv venv "${READTHEDOCS_VIRTUALENV_PATH}"
install:
- UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --group docs

# Build documentation with Mkdocs
mkdocs:
configuration: mkdocs.yml
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,11 @@ simplify interaction with `filesystem_spec`. Think of the `UPath` class in terms
of the following code:

```python
from pathlib import Path
from pathlib_abc import ReadablePath, WritablePath
from typing import Any, Mapping
from fsspec import AbstractFileSystem

class UPath(Path):
class UPath(ReadablePath, WriteablePath):
# the real implementation is more complex, but this is the general idea

@property
Expand Down
16 changes: 16 additions & 0 deletions docs/_plugins/copy_changelog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations

from pathlib import Path

THIS_DIR = Path(__file__).parent
DOCS_DIR = THIS_DIR.parent
PROJECT_ROOT = DOCS_DIR.parent


def on_pre_build(**_) -> None:
"""Add changelog to docs/changelog.md"""
cl_now = PROJECT_ROOT.joinpath("CHANGELOG.md").read_text(encoding="utf-8")

f_doc = DOCS_DIR.joinpath("changelog.md")
if not f_doc.is_file() or f_doc.read_text(encoding="utf-8") != cl_now:
f_doc.write_text(cl_now, encoding="utf-8")
67 changes: 67 additions & 0 deletions docs/api/extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Extensions :puzzle_piece:

The extensions module provides a base class for extending UPath functionality while maintaining
compatibility with all filesystem implementations.

## ProxyUPath

::: upath.extensions.ProxyUPath
options:
heading_level: 3
show_root_heading: true
show_root_full_path: false
members: false
show_bases: true

---

## Usage Example

`ProxyUPath` allows you to extend the UPath interface with additional methods while
preserving compatibility with all supported filesystem implementations. It acts as a
wrapper around any UPath instance.

### Creating a Custom Extension

```python
from upath import UPath
from upath.extensions import ProxyUPath

class MyCustomPath(ProxyUPath):
"""Custom path with additional functionality"""

def custom_method(self) -> str:
"""Add your custom functionality here"""
return f"Custom processing for: {self.path}"

def enhanced_read(self) -> str:
"""Enhanced read with preprocessing"""
content = self.read_text()
# Add custom processing
return content.upper()

# Use with any filesystem
s3_path = MyCustomPath("s3://bucket/file.txt")
local_path = MyCustomPath("/tmp/file.txt")
gcs_path = MyCustomPath("gs://bucket/file.txt")

# All standard UPath methods work
print(s3_path.exists())
print(local_path.parent)

# Always a subclass of your class
assert isinstance(s3_path, MyCustomPath)
assert isinstance(local_path, MyCustomPath)

# Plus your custom methods
print(s3_path.custom_method())
content = local_path.enhanced_read()
```

---

## See Also :link:

- [UPath](index.md) - Main UPath class documentation
- [Implementations](implementations.md) - Built-in UPath subclasses
- [Registry](registry.md) - Implementation registry
Loading