Skip to content

Commit 94fba8f

Browse files
authored
docs: fix subclass instructions in usage (#475)
1 parent 1aec8ff commit 94fba8f

File tree

1 file changed

+55
-3
lines changed

1 file changed

+55
-3
lines changed

docs/usage.md

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,21 @@ with fs.open(path_str, 'rb') as f:
227227

228228
### How do I create a custom UPath for a new filesystem?
229229

230-
Subclass `UPath` and register it:
230+
Let's say you have an fsspec filesystem with protocol `myproto` and the default
231+
implementation does not correctly work for `.is_dir()`. You can then subclass
232+
`UPath` and register your implementation:
231233

232234
```python
233235
from upath import UPath
234236
from upath.registry import register_implementation
235237

236238
class MyCustomPath(UPath):
237-
def custom_method(self):
238-
return f"Custom behavior for {self}"
239+
240+
# fix specific methods if the filesystem is a bit non-standard
241+
def is_dir(self, *, follow_symlinks=True):
242+
# some special way to check if it's a dir
243+
is_dir = ...
244+
return is_dir
239245

240246
# Register for your protocol
241247
register_implementation("myproto", MyCustomPath)
@@ -244,6 +250,52 @@ register_implementation("myproto", MyCustomPath)
244250
my_path = UPath("myproto://server/path")
245251
```
246252

253+
!!! note "don't extend the API in your subclass"
254+
255+
You should not extend the API in your UPath subclass.
256+
If you want to add new methods please use `upath.extensions.ProxyUPath` as a base class
257+
258+
### How do I add custom methods to UPath?
259+
260+
If you need to add domain-specific methods (like `.download()` or `.upload()`), use `ProxyUPath` instead of subclassing `UPath` directly:
261+
262+
```python
263+
from upath import UPath
264+
from upath.extensions import ProxyUPath
265+
266+
class MyCustomPath(ProxyUPath):
267+
"""A path with extra convenience methods."""
268+
269+
def download(self, local_path):
270+
"""Download this remote file to a local path."""
271+
local = UPath(local_path)
272+
local.write_bytes(self.read_bytes())
273+
return local
274+
275+
def get_metadata(self):
276+
"""Get custom metadata for this file."""
277+
stat = self.stat()
278+
return {
279+
'size': stat.st_size,
280+
'modified': stat.st_mtime,
281+
'name': self.name,
282+
}
283+
284+
# Use it like a regular UPath
285+
path = MyCustomPath("s3://my-bucket/data.csv", anon=True)
286+
287+
# Access standard UPath methods
288+
print(path.exists())
289+
print(path.name)
290+
291+
# Use your custom methods
292+
metadata = path.get_metadata()
293+
path.download("/tmp/data.csv")
294+
```
295+
296+
The key difference: `ProxyUPath` wraps a `UPath` instance and delegates to it, while keeping your custom methods separate from the core pathlib API.
297+
298+
247299
---
248300

249301
## Supported Filesystems

0 commit comments

Comments
 (0)