Repository: drivendataorg/cloudpathlib
Pull request #480 (2024-10-22 00:44:43)

Fix CloudPath.__truediv__ to return NotImplemented
Return `NotImplemented` for `CloudPath.__truediv__` in order to support operands that have implemented an `__rtruediv__` that works with `CloudPath`. 

Addresses an issue regarding compatibility with pandas-path surfaced in this issue:

- https://github.com/drivendataorg/pandas-path/issues/12#issuecomment-2427816667

github-actions[bot]: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY - APP ID SHA256: 9d0998be292ddace9530fffad95434f4e2279530e25cf278a25f07954faa426e -->
🚀 Deployed on https://deploy-preview-480--gallant-agnesi-5f7bb3.netlify.app
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/drivendataorg/cloudpathlib/pull/480?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 91.6%. Comparing base [(`5f5e054`)](https://app.codecov.io/gh/drivendataorg/cloudpathlib/commit/5f5e05404a00f2dcd51c5ea540e59abb10462403?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) to head [(`279fa86`)](https://app.codecov.io/gh/drivendataorg/cloudpathlib/commit/279fa868e68c80bf59d3e0666ab262817afe9a4c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff            @@
##           master    #480     +/-   ##
========================================
- Coverage    94.4%   91.6%   -2.8%     
========================================
  Files          23      23             
  Lines        1776    1776             
========================================
- Hits         1677    1628     -49     
- Misses         99     148     +49     
```

| [Files with missing lines](https://app.codecov.io/gh/drivendataorg/cloudpathlib/pull/480?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) | Coverage Δ | |
|---|---|---|
| [cloudpathlib/cloudpath.py](https://app.codecov.io/gh/drivendataorg/cloudpathlib/pull/480?src=pr&el=tree&filepath=cloudpathlib%2Fcloudpath.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL2Nsb3VkcGF0aC5weQ==) | `90.9% <100.0%> (-4.1%)` | :arrow_down: |

... and [3 files with indirect coverage changes](https://app.codecov.io/gh/drivendataorg/cloudpathlib/pull/480/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg)

</details>

Patch:
diff --git a/HISTORY.md b/HISTORY.md
index 1dd1cae..b39bee8 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,9 @@
 # cloudpathlib Changelog
 
+## Unreleased
+
+- Fixed `CloudPath(...) / other` to correctly attempt to fall back on `other`'s `__rtruediv__` implementation, in order to support classes that explicitly support the `/` with a `CloudPath` instance. Previously, this would always raise a `TypeError` if `other` were not a `str` or `PurePosixPath`. (PR [#479](https://github.com/drivendataorg/cloudpathlib/pull/479))
+
 ## v0.20.0 (2024-10-18)
 
 - Added support for custom schemes in CloudPath and Client subclases. (Issue [#466](https://github.com/drivendataorg/cloudpathlib/issues/466), PR [#467](https://github.com/drivendataorg/cloudpathlib/pull/467))
diff --git a/cloudpathlib/cloudpath.py b/cloudpathlib/cloudpath.py
index ef28d5e..5845e92 100644
--- a/cloudpathlib/cloudpath.py
+++ b/cloudpathlib/cloudpath.py
@@ -888,7 +888,7 @@ class CloudPath(metaclass=CloudPathMeta):
 
     def __truediv__(self, other: Union[str, PurePosixPath]) -> Self:
         if not isinstance(other, (str, PurePosixPath)):
-            raise TypeError(f"Can only join path {repr(self)} with strings or posix paths.")
+            return NotImplemented
 
         return self._dispatch_to_path("__truediv__", other)
 


Test patch:
diff --git a/tests/test_cloudpath_manipulation.py b/tests/test_cloudpath_manipulation.py
index d42b154..b9e7066 100644
--- a/tests/test_cloudpath_manipulation.py
+++ b/tests/test_cloudpath_manipulation.py
@@ -204,3 +204,28 @@ def test_parser(rig):
     else:
         # always posixpath since our dispath goes to PurePosixPath
         assert rig.create_cloud_path("a/b/c").parser == posixpath
+
+
+def test_truediv_fallback(rig):
+    """Another class with __rtruediv__ method should be able to use / operator with CloudPath."""
+
+    class CustomClassSupportsCloudPath:
+        def __init__(self, value: str):
+            self.value = value
+
+        def __rtruediv__(self, other):
+            if isinstance(other, CloudPath):
+                return other / self.value
+            return NotImplemented
+
+    assert rig.create_cloud_path("a/b") / CustomClassSupportsCloudPath(
+        "c"
+    ) == rig.create_cloud_path("a/b/c")
+
+    # Expect TypeError if / operation with CloudPath is not supported
+    class CustomClassDoesNotSupportCloudPath:
+        def __init__(self, value: str):
+            self.value = value
+
+    with pytest.raises(TypeError):
+        rig.create_cloud_path("a/b") / CustomClassDoesNotSupportCloudPath("c")