Repository: drivendataorg/cloudpathlib
Pull request #257 (2022-08-18 18:08:02)

Use abc.ABC as baseclass for AnyPath to fix issubclass behavior (#251)
* Use abc.ABC as baseclass for AnyPath

* add type ignore for ABC.register

---------------

Local branch to run live tests

github-actions[bot]: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY -->
🚀 Deployed on https://deploy-preview-257--gallant-agnesi-5f7bb3.netlify.app
codecov-commenter: # [Codecov](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) Report
> Merging [#257](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) (b5cdc3f) into [master](https://codecov.io/gh/drivendataorg/cloudpathlib/commit/1f28327d0c907287b24a943751257eac81d9f9a1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) (1f28327) will **decrease** coverage by `0.4%`.
> The diff coverage is `100.0%`.

```diff
@@           Coverage Diff            @@
##           master    #257     +/-   ##
========================================
- Coverage    94.8%   94.3%   -0.5%     
========================================
  Files          21      21             
  Lines        1323    1318      -5     
========================================
- Hits         1255    1244     -11     
- Misses         68      74      +6     
```


| [Impacted Files](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg) | Coverage Δ | |
|---|---|---|
| [cloudpathlib/anypath.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL2FueXBhdGgucHk=) | `100.0% <100.0%> (ø)` | |
| [cloudpathlib/\_\_init\_\_.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL19faW5pdF9fLnB5) | `92.8% <0.0%> (-7.2%)` | :arrow_down: |
| [cloudpathlib/s3/s3client.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL3MzL3MzY2xpZW50LnB5) | `92.9% <0.0%> (-2.7%)` | :arrow_down: |
| [cloudpathlib/gs/gsclient.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL2dzL2dzY2xpZW50LnB5) | `92.8% <0.0%> (-1.8%)` | :arrow_down: |
| [cloudpathlib/local/implementations/azure.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL2xvY2FsL2ltcGxlbWVudGF0aW9ucy9henVyZS5weQ==) | `97.5% <0.0%> (-0.1%)` | :arrow_down: |
| [cloudpathlib/local/implementations/gs.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL2xvY2FsL2ltcGxlbWVudGF0aW9ucy9ncy5weQ==) | `100.0% <0.0%> (ø)` | |
| [cloudpathlib/local/implementations/s3.py](https://codecov.io/gh/drivendataorg/cloudpathlib/pull/257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=drivendataorg#diff-Y2xvdWRwYXRobGliL2xvY2FsL2ltcGxlbWVudGF0aW9ucy9zMy5weQ==) | `100.0% <0.0%> (ø)` | |


Patch:
diff --git a/cloudpathlib/anypath.py b/cloudpathlib/anypath.py
index de56f33..197dbe6 100644
--- a/cloudpathlib/anypath.py
+++ b/cloudpathlib/anypath.py
@@ -1,4 +1,5 @@
 import os
+from abc import ABC
 from pathlib import Path
 from typing import Union
 
@@ -6,19 +7,7 @@ from .cloudpath import InvalidPrefixError, CloudPath
 from .exceptions import AnyPathTypeError
 
 
-class AnyPathMeta(type):
-    """Metaclass for AnyPath that implements special methods so that AnyPath works as a virtual
-    superclass when using isinstance or issubclass checks on CloudPath or Path inputs. See
-    [PEP 3119](https://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass)."""
-
-    def __instancecheck__(cls, inst):
-        return isinstance(inst, CloudPath) or isinstance(inst, Path)
-
-    def __subclasscheck__(cls, sub):
-        return issubclass(sub, CloudPath) or issubclass(sub, Path)
-
-
-class AnyPath(metaclass=AnyPathMeta):
+class AnyPath(ABC):
     """Polymorphic virtual superclass for CloudPath and pathlib.Path. Constructing an instance will
     automatically dispatch to CloudPath or Path based on the input. It also supports both
     isinstance and issubclass checks.
@@ -55,6 +44,10 @@ class AnyPath(metaclass=AnyPathMeta):
         return cls.__new__(cls, value)
 
 
+AnyPath.register(CloudPath)  # type: ignore
+AnyPath.register(Path)
+
+
 def to_anypath(s: Union[str, os.PathLike]) -> Union[CloudPath, Path]:
     """Convenience method to convert a str or os.PathLike to the
     proper Path or CloudPath object using AnyPath.


Test patch:
diff --git a/tests/test_anypath.py b/tests/test_anypath.py
index 90c97bd..47cac83 100644
--- a/tests/test_anypath.py
+++ b/tests/test_anypath.py
@@ -36,3 +36,7 @@ def test_anypath_cloudpath(rig):
 def test_anypath_bad_input():
     with pytest.raises(AnyPathTypeError):
         AnyPath(0)
+
+
+def test_anypath_subclass_anypath():
+    assert issubclass(AnyPath, AnyPath)