Skip to content

Commit 7f0e9b2

Browse files
authored
upath.core: deprecate _protocol_dispatch=False (#454)
* upath.core: deprecate _protocol_dispatch=False * readme: update the extensions section
1 parent ca1f993 commit 7f0e9b2

File tree

3 files changed

+41
-13
lines changed

3 files changed

+41
-13
lines changed

README.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -602,25 +602,28 @@ class MyProtoPath(UPath):
602602
return args, protocol, storage_options
603603
```
604604

605-
#### Stopping UPath's subclass dispatch mechanism
605+
#### Extending UPath's API interface
606606

607-
There are cases for which you want to disable the protocol dispatch mechanism of
608-
the `UPath.__new__` constructor. For example if you want to extend the class API
609-
of your `UPath` implementation, and use it as the base class for other, directly
610-
instantiated subclasses. Together with other customization options this can be a
611-
useful feature. Please be aware that in this case all protocols are handled with
612-
the default implementation in UPath. Please always feel free to open an issue in
613-
the issue tracker to discuss your use case. We're happy to help with finding the
614-
most maintainable solution.
607+
If you want to extend the class API
608+
of your `UPath` implementation, it's recommended to subclass
609+
`upath.extensions.ProxyUPath`. It's a thin proxy layer around
610+
the public methods and attributes of a UPath instance.
615611

616612
```python
617-
class ExtraUPath(UPath):
618-
_protocol_dispatch = False # disable the registry return an ExtraUPath
613+
from upath.extensions import ProxyUPath
614+
615+
class ExtraUPath(ProxyUPath):
619616

620617
def some_extra_method(self) -> str:
621-
return "hello world"
618+
return f"hello world {self.name}"
619+
620+
e0 = ExtraUPath("s3://bucket/foo.txt")
621+
e1 = ExtraUPath("memory://bar/baz.txt")
622622

623-
assert ExtraUPath("s3://bucket/file.txt").some_extra_method() == "hello world"
623+
assert e0.some_extra_method() == "hello world foo.txt"
624+
assert isinstance(e0, ExtraUPath)
625+
assert e1.some_extra_method() == "hello world baz.txt"
626+
assert isinstance(e1, ExtraUPath)
624627
```
625628

626629
## Migration Guide
@@ -729,6 +732,12 @@ path = UPath("memory:///file.txt")
729732
os.remove(path) # TypeError: expected str, bytes or os.PathLike, not MemoryPath
730733
```
731734

735+
#### Extending UPath via `_protocol_dispatch=False`
736+
737+
If you previously used `_protocol_dipatch=False` to enable extension of the
738+
UPath API, we now recommend to subclass `upath.extensions.ProxyUPath`. See
739+
the example in the main docs.
740+
732741
### migrating to `v0.2.0`
733742

734743
### _FSSpecAccessor subclasses with custom filesystem access methods

upath/core.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ def __new__(
337337
#
338338
# THIS IS DEPRECATED!
339339
# Use upath.extensions.ProxyUPath to extend the UPath API
340+
warnings.warn(
341+
f"{cls.__name__}._protocol_dispatch = False is deprecated and"
342+
" will be removed in future universal_pathlib versions."
343+
" To extend the UPath API, subclass upath.extensions.ProxyUPath",
344+
DeprecationWarning,
345+
stacklevel=2,
346+
)
340347
upath_cls = cls
341348

342349
if issubclass(upath_cls, cls):

upath/tests/test_extensions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22

3+
from upath import UPath
34
from upath.extensions import ProxyUPath
45
from upath.implementations.local import FilePath
56
from upath.implementations.memory import MemoryPath
@@ -53,3 +54,14 @@ def write_bytes_reversed(self, value):
5354

5455
r.parent.joinpath("file2").write_bytes_reversed(b"dlrow olleh")
5556
assert b.joinpath("file2").read_bytes() == b"hello world"
57+
58+
59+
def test_protocol_dispatch_deprecation_warning():
60+
61+
class MyPath(UPath):
62+
_protocol_dispatch = False
63+
64+
with pytest.warns(DeprecationWarning, match="_protocol_dispatch = False"):
65+
a = MyPath(".", protocol="memory")
66+
67+
assert isinstance(a, MyPath)

0 commit comments

Comments
 (0)