Repository: ioos/compliance-checker

Issue:
CheckSuite.load_dataset throws error when passed pathlib.Path
When I pass `CheckSuite.load_dataset()` a `pathlib.Path`, `urlparse()` throws an `AttributeError`. 

```py
ds = check_suite.load_dataset(ds_path)

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-9-51af4cea0bdf> in <module>
----> 1 cs_ds = check_suite.load_dataset(ds_path)

/usr/local/miniconda3/envs/neracoos-dagster/lib/python3.9/site-packages/compliance_checker/suite.py in load_dataset(self, ds_str)
    820         # If it's a remote URL load it as a remote resource, otherwise treat it
    821         # as a local resource.
--> 822         pr = urlparse(ds_str)
    823         if pr.netloc:
    824             return self.load_remote_dataset(ds_str)

/usr/local/miniconda3/envs/neracoos-dagster/lib/python3.9/urllib/parse.py in urlparse(url, scheme, allow_fragments)
    387     Note that % escapes are not expanded.
    388     """
--> 389     url, scheme, _coerce_result = _coerce_args(url, scheme)
    390     splitresult = urlsplit(url, scheme, allow_fragments)
    391     scheme, netloc, url, query, fragment = splitresult

/usr/local/miniconda3/envs/neracoos-dagster/lib/python3.9/urllib/parse.py in _coerce_args(*args)
    123     if str_input:
    124         return args + (_noop,)
--> 125     return _decode_args(args) + (_encode_result,)
    126 
    127 # Result objects are more helpful than simple tuples

/usr/local/miniconda3/envs/neracoos-dagster/lib/python3.9/urllib/parse.py in _decode_args(args, encoding, errors)
    107 def _decode_args(args, encoding=_implicit_encoding,
    108                        errors=_implicit_errors):
--> 109     return tuple(x.decode(encoding, errors) if x else '' for x in args)
    110 
    111 def _coerce_args(*args):

/usr/local/miniconda3/envs/neracoos-dagster/lib/python3.9/urllib/parse.py in <genexpr>(.0)
    107 def _decode_args(args, encoding=_implicit_encoding,
    108                        errors=_implicit_errors):
--> 109     return tuple(x.decode(encoding, errors) if x else '' for x in args)
    110 
    111 def _coerce_args(*args):

AttributeError: 'PosixPath' object has no attribute 'decode'
```

https://github.com/ioos/compliance-checker/blob/1cef413574b86f1a76df0cf4f1c9c8edba4e3e69/compliance_checker/suite.py#L813-L826

<summary>Environment</summary>
<details>

```zsh
➜ conda list
# packages in environment at /usr/local/miniconda3/envs/neracoos-dagster:
#
# Name                    Version                   Build  Channel
alembic                   1.6.5              pyhd8ed1ab_0    conda-forge
aniso8601                 7.0.0                      py_0    conda-forge
antlr-python-runtime      4.7.2           py39h6e9494a_1003    conda-forge
appnope                   0.1.2            py39h6e9494a_1    conda-forge
argh                      0.26.2          pyh9f0ad1d_1002    conda-forge
attrs                     21.2.0             pyhd8ed1ab_0    conda-forge
backcall                  0.2.0              pyh9f0ad1d_0    conda-forge
backports                 1.0                        py_2    conda-forge
backports.functools_lru_cache 1.6.4              pyhd8ed1ab_0    conda-forge
bleach                    3.3.0              pyh44b312d_0    conda-forge
bokeh                     2.3.2            py39h6e9494a_0    conda-forge
brotlipy                  0.7.0           py39hcbf5805_1001    conda-forge
bzip2                     1.0.8                h0d85af4_4    conda-forge
c-ares                    1.17.1               h0d85af4_1    conda-forge
ca-certificates           2021.10.8            h033912b_0    conda-forge
cc-plugin-ncei            2.0.2                      py_3    conda-forge
certifi                   2021.10.8        py39h6e9494a_1    conda-forge
cf-units                  3.0.1            py39hc89836e_2    conda-forge
cffi                      1.14.5           py39h319c39b_0    conda-forge
cftime                    1.5.0            py39hc89836e_0    conda-forge
chardet                   4.0.0            py39h6e9494a_1    conda-forge
click                     8.0.1            py39h6e9494a_0    conda-forge
cloudpickle               1.6.0                      py_0    conda-forge
coloredlogs               14.0             py39hde42818_2    conda-forge
compliance-checker        5.0.0              pyhd8ed1ab_0    conda-forge
croniter                  1.0.13             pyhd8ed1ab_0    conda-forge
cryptography              3.4.7            py39ha2c9959_0    conda-forge
curl                      7.77.0               hb861fe1_0    conda-forge
cytoolz                   0.11.0           py39hcbf5805_3    conda-forge
dagit                     0.11.8             pyhd8ed1ab_1    conda-forge
dagster                   0.11.8           py39h6e9494a_1    conda-forge
dagster-graphql           0.11.8             pyhd8ed1ab_1    conda-forge
dask                      2021.6.0           pyhd8ed1ab_0    conda-forge
dask-core                 2021.6.0           pyhd8ed1ab_0    conda-forge
dataclasses               0.8                pyhc8e2a94_1    conda-forge
decorator                 5.0.9              pyhd8ed1ab_0    conda-forge
defusedxml                0.7.1              pyhd8ed1ab_0    conda-forge
distributed               2021.6.0         py39h6e9494a_0    conda-forge
docstring_parser          0.7.1                      py_0    conda-forge
entrypoints               0.3             pyhd8ed1ab_1003    conda-forge
enum-compat               0.0.3            py39hde42818_2    conda-forge
expat                     2.4.4                he49afe7_0    conda-forge
flask                     2.0.1              pyhd8ed1ab_0    conda-forge
flask-cors                3.0.10             pyhd8ed1ab_0    conda-forge
flask-graphql             2.0.1                      py_0    conda-forge
flask-sockets             0.2.1                      py_0    conda-forge
freetype                  2.10.4               h4cff582_1    conda-forge
fsspec                    2021.5.0           pyhd8ed1ab_0    conda-forge
future                    0.18.2           py39h6e9494a_3    conda-forge
geos                      3.10.2               he49afe7_0    conda-forge
gevent                    21.1.2           py39h89e85a6_0    conda-forge
gevent-websocket          0.10.1                     py_0    conda-forge
gql                       2.0.0              pyh9f0ad1d_0    conda-forge
graphene                  2.1.8                      py_0    conda-forge
graphql-core              2.3.2              pyh9f0ad1d_0    conda-forge
graphql-relay             2.0.1                      py_0    conda-forge
graphql-server-core       2.0.0              pyh8c360ce_1    conda-forge
graphql-ws                0.3.1              pyh9f0ad1d_1    conda-forge
greenlet                  1.1.0            py39h9fcab8e_0    conda-forge
grpcio                    1.38.0           py39hb974310_0    conda-forge
grpcio-health-checking    1.38.0             pyhd8ed1ab_0    conda-forge
hdf4                      4.2.13               h39711bb_2
hdf5                      1.10.6          nompi_hc5d9132_1114    conda-forge
heapdict                  1.0.1                      py_0    conda-forge
humanfriendly             9.1              py39h6e9494a_0    conda-forge
icu                       68.2                 he49afe7_0    conda-forge
idna                      2.10               pyh9f0ad1d_0    conda-forge
importlib-metadata        4.5.0            py39h6e9494a_0    conda-forge
ipykernel                 5.5.5            py39h71a6800_0    conda-forge
ipython                   7.24.1           py39h71a6800_0    conda-forge
ipython_genutils          0.2.0                      py_1    conda-forge
isodate                   0.6.1              pyhd8ed1ab_0    conda-forge
itsdangerous              2.0.1              pyhd8ed1ab_0    conda-forge
jbig                      2.1               h0d85af4_2003    conda-forge
jedi                      0.18.0           py39h6e9494a_2    conda-forge
jinja2                    3.0.1              pyhd8ed1ab_0    conda-forge
jpeg                      9d                   hbcb3906_0    conda-forge
jsonschema                3.2.0              pyhd8ed1ab_3    conda-forge
jupyter_client            6.1.12             pyhd8ed1ab_0    conda-forge
jupyter_core              4.7.1            py39h6e9494a_0    conda-forge
krb5                      1.19.1               hcfbf3a7_0    conda-forge
lcms2                     2.12                 h577c468_0    conda-forge
lerc                      2.2.1                h046ec9c_0    conda-forge
libblas                   3.9.0                9_openblas    conda-forge
libcblas                  3.9.0                9_openblas    conda-forge
libcurl                   7.77.0               hf45b732_0    conda-forge
libcxx                    11.1.0               habf9029_0    conda-forge
libdeflate                1.7                  h35c211d_5    conda-forge
libedit                   3.1.20191231         h0678c8f_2    conda-forge
libev                     4.33                 haf1e3a3_1    conda-forge
libffi                    3.3                  h046ec9c_2    conda-forge
libgfortran               5.0.0           9_3_0_h6c81a4c_22    conda-forge
libgfortran5              9.3.0               h6c81a4c_22    conda-forge
libiconv                  1.16                 haf1e3a3_0    conda-forge
liblapack                 3.9.0                9_openblas    conda-forge
libnetcdf                 4.6.1                hfd9a460_4
libnghttp2                1.43.0               h07e645a_0    conda-forge
libopenblas               0.3.15          openmp_h5e1b9a4_1    conda-forge
libpng                    1.6.37               h7cec526_2    conda-forge
libprotobuf               3.17.2               hcf210ce_0    conda-forge
libsodium                 1.0.18               hbcb3906_1    conda-forge
libssh2                   1.9.0                h52ee1ee_6    conda-forge
libtiff                   4.3.0                h1167814_1    conda-forge
libuv                     1.41.0               hbcf498f_0    conda-forge
libwebp-base              1.2.0                h0d85af4_2    conda-forge
libxml2                   2.9.12               h93ec3fd_0    conda-forge
libxslt                   1.1.33               h5739fc3_2    conda-forge
libzip                    1.7.3                hbc046b2_0    conda-forge
llvm-openmp               11.1.0               hda6cdc1_1    conda-forge
locket                    0.2.0                      py_2    conda-forge
lxml                      4.7.1            py39hf41e7f8_0    conda-forge
lz4-c                     1.9.3                h046ec9c_0    conda-forge
mako                      1.1.4              pyh44b312d_0    conda-forge
markdown-it-py            1.1.0              pyhd8ed1ab_0    conda-forge
markupsafe                2.0.1            py39h89e85a6_0    conda-forge
matplotlib-inline         0.1.2              pyhd8ed1ab_2    conda-forge
mdit-py-plugins           0.2.8              pyhd8ed1ab_0    conda-forge
mistune                   0.8.4           py39hcbf5805_1003    conda-forge
msgpack-python            1.0.2            py39hedf5dff_1    conda-forge
nbconvert                 5.6.0                      py_0    conda-forge
nbformat                  5.1.3              pyhd8ed1ab_0    conda-forge
ncurses                   6.2                  h2e338ed_4    conda-forge
netcdf4                   1.5.7            py39h93ad9c5_0
numpy                     1.20.3           py39h7eed0ac_1    conda-forge
olefile                   0.46               pyh9f0ad1d_1    conda-forge
openjpeg                  2.4.0                h6e7aa92_1    conda-forge
openssl                   1.1.1l               h0d85af4_0    conda-forge
owslib                    0.25.0             pyhd8ed1ab_0    conda-forge
packaging                 20.9               pyh44b312d_0    conda-forge
pandas                    1.2.4            py39h4d6be9b_0    conda-forge
pandoc                    2.14.0.1             h0d85af4_0    conda-forge
pandocfilters             1.4.2                      py_1    conda-forge
parso                     0.8.2              pyhd8ed1ab_0    conda-forge
partd                     1.2.0              pyhd8ed1ab_0    conda-forge
pendulum                  2.1.2              pyhd8ed1ab_1    conda-forge
pexpect                   4.8.0              pyh9f0ad1d_2    conda-forge
pickleshare               0.7.5                   py_1003    conda-forge
pillow                    8.2.0            py39h5fdd921_1    conda-forge
pip                       21.1.2             pyhd8ed1ab_0    conda-forge
proj                      8.0.1                h1512c50_0    conda-forge
promise                   2.3              py39h6e9494a_3    conda-forge
prompt-toolkit            3.0.18             pyha770c72_0    conda-forge
protobuf                  3.17.2           py39h9fcab8e_0    conda-forge
psutil                    5.8.0            py39h89e85a6_1    conda-forge
ptyprocess                0.7.0              pyhd3deb0d_0    conda-forge
pycparser                 2.20               pyh9f0ad1d_2    conda-forge
pydantic                  1.8.2            py39h89e85a6_0    conda-forge
pygeoif                   0.7                        py_1    conda-forge
pygments                  2.9.0              pyhd8ed1ab_0    conda-forge
pyopenssl                 20.0.1             pyhd8ed1ab_0    conda-forge
pyparsing                 2.4.7              pyh9f0ad1d_0    conda-forge
pyproj                    3.3.0            py39h7b8b08e_1    conda-forge
pyrsistent                0.17.3           py39hcbf5805_2    conda-forge
pysocks                   1.7.1            py39h6e9494a_3    conda-forge
python                    3.9.4           h9133fd0_0_cpython    conda-forge
python-dateutil           2.8.1                      py_0    conda-forge
python-editor             1.0.4                      py_0    conda-forge
python-frontmatter        1.0.0                    pypi_0    pypi
python_abi                3.9                      1_cp39    conda-forge
pytz                      2021.1             pyhd8ed1ab_0    conda-forge
pytzdata                  2020.1             pyh9f0ad1d_0    conda-forge
pyyaml                    5.4.1            py39hcbf5805_0    conda-forge
pyzmq                     22.1.0           py39h7fec2f1_0    conda-forge
readline                  8.1                  h05e3726_0    conda-forge
regex                     2022.1.18        py39h89e85a6_0    conda-forge
requests                  2.25.1             pyhd3deb0d_0    conda-forge
rx                        1.6.1                      py_0    conda-forge
setuptools                49.6.0           py39h6e9494a_3    conda-forge
shapely                   1.8.0            py39hbfbc381_5    conda-forge
six                       1.16.0             pyh6c4a22f_0    conda-forge
sortedcontainers          2.4.0              pyhd8ed1ab_0    conda-forge
sqlalchemy                1.4.17           py39h89e85a6_0    conda-forge
sqlite                    3.35.5               h44b9ce1_0    conda-forge
tabulate                  0.8.9              pyhd8ed1ab_0    conda-forge
tblib                     1.7.0              pyhd8ed1ab_0    conda-forge
testpath                  0.5.0              pyhd8ed1ab_0    conda-forge
tk                        8.6.10               h0419947_1    conda-forge
toolz                     0.11.1                     py_0    conda-forge
toposort                  1.6                pyhd8ed1ab_0    conda-forge
tornado                   6.1              py39hcbf5805_1    conda-forge
tqdm                      4.61.0             pyhd8ed1ab_0    conda-forge
traitlets                 5.0.5                      py_0    conda-forge
typing-extensions         3.10.0.0             hd8ed1ab_0    conda-forge
typing_extensions         3.10.0.0           pyha770c72_0    conda-forge
tzdata                    2021a                he74cb21_0    conda-forge
tzlocal                   1.5.1                      py_0    conda-forge
udunits2                  2.2.28               h06ef574_0    conda-forge
urllib3                   1.26.5             pyhd8ed1ab_0    conda-forge
validators                0.18.2             pyhd3deb0d_0    conda-forge
watchdog                  2.1.2            py39h9c2f2d1_0    conda-forge
wcwidth                   0.2.5              pyh9f0ad1d_2    conda-forge
webencodings              0.5.1                      py_1    conda-forge
werkzeug                  2.0.1              pyhd8ed1ab_0    conda-forge
wheel                     0.36.2             pyhd3deb0d_0    conda-forge
xarray                    0.18.2             pyhd8ed1ab_0    conda-forge
xz                        5.2.5                haf1e3a3_1    conda-forge
yaml                      0.2.5                haf1e3a3_0    conda-forge
zeromq                    4.3.4                h1c7c35f_0    conda-forge
zict                      2.0.0                      py_0    conda-forge
zipp                      3.4.1              pyhd8ed1ab_0    conda-forge
zlib                      1.2.11            h7795811_1010    conda-forge
zope.event                4.5.0              pyh9f0ad1d_0    conda-forge
zope.interface            5.4.0            py39h89e85a6_0    conda-forge
zstd                      1.5.0                h582d3a0_0    conda-forge
```

</details>

cc @ocefpaf 


Discussion:

Resolving patch:
diff --git a/compliance_checker/suite.py b/compliance_checker/suite.py
--- a/compliance_checker/suite.py
+++ b/compliance_checker/suite.py
@@ -16,6 +16,7 @@
 from datetime import datetime, timezone
 from distutils.version import StrictVersion
 from operator import itemgetter
+from pathlib import Path
 from urllib.parse import urlparse
 
 import requests
@@ -817,6 +818,9 @@ def load_dataset(self, ds_str):
 
         :param str ds_str: URL of the resource to load
         """
+        if isinstance(ds_str, Path):
+            ds_str = str(ds_str)
+
         # If it's a remote URL load it as a remote resource, otherwise treat it
         # as a local resource.
         pr = urlparse(ds_str)


Test patch:
diff --git a/compliance_checker/tests/test_suite.py b/compliance_checker/tests/test_suite.py
--- a/compliance_checker/tests/test_suite.py
+++ b/compliance_checker/tests/test_suite.py
@@ -2,6 +2,8 @@
 import os
 import unittest
 
+from pathlib import Path
+
 import numpy as np
 
 from pkg_resources import resource_filename
@@ -62,6 +64,13 @@ def test_suite(self):
         ds = self.cs.load_dataset(static_files["2dim"])
         self.cs.run(ds, [], "acdd")
 
+
+    def test_suite_pathlib(self):
+        path_obj = Path(static_files["2dim"])
+        ds = self.cs.load_dataset(path_obj)
+        self.cs.run(ds, [], "acdd")
+
+
     def test_unicode_formatting(self):
         ds = self.cs.load_dataset(static_files["bad_region"])
         score_groups = self.cs.run(ds, [], "cf")