Repository: drivendataorg/cloudpathlib (python)

Issue:
Module fails to import when Python is ran with -OO
Since `-OO` removes docstrings, the module fails on import as shown in the following trace:

```python
[...]
    from cloudpathlib import AnyPath, CloudPath
  File "/home/javier/.virtualenvs/WebsiteTopicClassifier/lib/python3.6/site-packages/cloudpathlib/__init__.py", line 3, in <module>
    from .anypath import AnyPath
  File "/home/javier/.virtualenvs/WebsiteTopicClassifier/lib/python3.6/site-packages/cloudpathlib/anypath.py", line 5, in <module>
    from .cloudpath import InvalidPrefixError, CloudPath
  File "/home/javier/.virtualenvs/WebsiteTopicClassifier/lib/python3.6/site-packages/cloudpathlib/cloudpath.py", line 136, in <module>
    class CloudPath(metaclass=CloudPathMeta):
  File "/home/javier/.virtualenvs/WebsiteTopicClassifier/lib/python3.6/site-packages/cloudpathlib/cloudpath.py", line 127, in __init__
    docstring = getattr(Path, attr).__doc__ + " _(Docstring copied from pathlib.Path)_"
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
```

Pull request:
Skip docstrings if running with `-OO`
Manually tested and confirmed that PyPI version fails and this version succeeds.

Fixes #238 

Patch:
diff --git a/MANIFEST.in b/MANIFEST.in
index bb910eb..8f95f85 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include README.md
 include LICENSE
 include requirements.txt
+include cloudpathlib/py.typed
\ No newline at end of file
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.
diff --git a/cloudpathlib/cloudpath.py b/cloudpathlib/cloudpath.py
index 7a013b1..be93bbc 100644
--- a/cloudpathlib/cloudpath.py
+++ b/cloudpathlib/cloudpath.py
@@ -122,7 +122,7 @@ class CloudPathMeta(abc.ABCMeta):
             if (
                 not attr.startswith("_")
                 and hasattr(Path, attr)
-                and hasattr(getattr(Path, attr), "__doc__")
+                and getattr(getattr(Path, attr), "__doc__", None)
             ):
                 docstring = getattr(Path, attr).__doc__ + " _(Docstring copied from pathlib.Path)_"
                 getattr(cls, attr).__doc__ = docstring
@@ -639,7 +639,6 @@ class CloudPath(metaclass=CloudPathMeta):
         else:
             return path_version
 
-    @property
     def stat(self):
         """Note: for many clients, we may want to override so we don't incur
         network costs since many of these properties are available as
diff --git a/cloudpathlib/py.typed b/cloudpathlib/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/requirements-dev.txt b/requirements-dev.txt
index d56ffef..49c7123 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -16,7 +16,7 @@ pandas
 pillow
 psutil
 pydantic
-pytest<7.0
+pytest
 pytest-cases
 pytest-cov
 python-dotenv
diff --git a/setup.py b/setup.py
index fd52edf..c4836ca 100644
--- a/setup.py
+++ b/setup.py
@@ -54,6 +54,7 @@ setup(
     include_package_data=True,
     name="cloudpathlib",
     packages=find_packages(exclude=["tests"]),
+    package_data={"cloudpathlib": ["py.typed"]},
     project_urls={
         "Bug Tracker": "https://github.com/drivendataorg/cloudpathlib/issues",
         "Documentation": "https://cloudpathlib.drivendata.org/",


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)