Repository: lucianopaz/compress_pickle

Issue:
Support `with open` context manager
Currently, the following snippet does not infer the compression scheme properly and errors:

```python
import compress_pickle as cpickle

with open('test.lzma', 'wb') as f:    # Same issue for other extensions
    cpickle.dump([1, 2, 3], f)
```

Which results in the following error:

```
env/lib/python3.8/site-packages/compress_pickle/utils.py in instantiate_compresser(compression, path, mode, set_default_extension, **kwargs)
    110         _path = _stringyfy_path(path)
    111     if compression == "infer":
--> 112         compression = _infer_compression_from_path(_path)
    113     compresser_class = get_compresser(compression)
    114     if set_default_extension and isinstance(path, PATH_TYPES):

UnboundLocalError: local variable '_path' referenced before assignment
```

While the docstring says "a file-like object (``io.BaseIO`` instances) [...] will be passed to the `BaseCompresser` class", this does not happen. I'd suggest grabbing the filename like so:

```python
    if isinstance(path, PATH_TYPES):
        _path = _stringyfy_path(path)
    elif isinstance(path, io.IOBase):
        _path = path.name                          # this would set _path to 'test.lzma' in the above example
    else:
        raise RuntimeError("Unrecognized path")

    if compression == "infer":
        compression = _infer_compression_from_path(_path)
```

The error would simply ensure that the variable `_path` is defined. Something more descriptive could be added.   

Any thoughts on this? I don't have time to submit a PR this week, but I'd be happy to at a later time. Thanks for this excellent library!

Comments:

Patch:
diff --git a/compress_pickle/utils.py b/compress_pickle/utils.py
index 4e226ad..a5284b1 100644
--- a/compress_pickle/utils.py
+++ b/compress_pickle/utils.py
@@ -105,10 +105,20 @@ def instantiate_compresser(
     BaseCompresser
         The compresser instance that will be used to create the byte stream from which a
         :class:`compress_pickle.picklers.base.BasePicklerIO` will read or write serialized objects.
+
+    Raises
+    ------
+    TypeError
+        If the supplied ``path`` is not a ``PATH_TYPES`` instance and the ``compression`` is "infer".
     """
     if isinstance(path, PATH_TYPES):
         _path = _stringyfy_path(path)
     if compression == "infer":
+        if not isinstance(path, PATH_TYPES):
+            raise TypeError(
+                f"Cannot infer the compression from a path that is not an instance of "
+                f"{PATH_TYPES}. Encountered {type(path)}"
+            )
         compression = _infer_compression_from_path(_path)
     compresser_class = get_compresser(compression)
     if set_default_extension and isinstance(path, PATH_TYPES):


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 6ec6fcc..2eeb45e 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -6,6 +6,7 @@ from compress_pickle.utils import (
     _stringyfy_path,
     _infer_compression_from_path,
     _set_default_extension,
+    instantiate_compresser,
 )
 
 
@@ -54,6 +55,15 @@ def test_infer_compression_from_path_io_type():
             _infer_compression_from_path(path)
 
 
+def test_instantiate_compresser_cannot_infer_compression():
+    with pytest.raises(
+        TypeError,
+        match="Cannot infer the compression from a path that is not an instance of ",
+    ):
+        with io.BytesIO() as path:
+            instantiate_compresser(compression="infer", path=path, mode="rb")
+
+
 # def test_known_compressions():
 #     kcn = get_known_compressions()
 #     assert all((cn in kcn for cn in COMPRESSION_NAMES))