Repository: gtsystem/python-remotezip

Issue:
Underlying stream is not seekable when entry is passed as file
Here is short code that cause error 


```
import h5py
from remotezip import RemoteZip


def main():
    remoteZip = RemoteZip(
        'https://docs-assets.developer.apple.com/ml-research/datasets/hypersim/v1/scenes/ai_001_001.zip')
    with remoteZip.open('ai_001_001/images/scene_cam_00_final_hdf5/frame.0000.residual.hdf5') as file:
        hdf = h5py.File(file, 'r')
        print(hdf.keys())


if __name__ == "__main__":
    main()
```


Discussion:

Patch:
diff --git a/README.md b/README.md
index 0c8ab8a..c20fa05 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,9 @@ To download the content, this library rely on the `requests` module. The constru
 Please look at the [zipfile](https://docs.python.org/3/library/zipfile.html#zipfile-objects) documentation for usage details.
 
 
-**NOTE**: `extractall()` and `testzip()` require to access the full content of the archive. If you need to use such methods, a full download of it would be probably more efficient.
+**NOTE**:
+* `extractall()` and `testzip()` require to access the full content of the archive. If you need to use such methods, a full download of it would be probably more efficient.
+* `RemoteZip.open()` now supports seek operations when reading archive members. However as the content is streamed and DEFLATE format doesn't support seek natively, any negative seek operation will result in a new remote request from the beginning of the member content. This is very inefficient, the recommandation is to use `RemoteZip.extract()` and then open and operate on the extracted file.
 
 ### Examples
 
@@ -138,6 +140,7 @@ How many requests will this module perform to download a member?
 * If the full archive content is smaller than **initial\_buffer\_size**, only one request will be needed.
 * Normally two requests are needed, one to download the central directory and one to download the archive member.
 * If the central directory is bigger than **initial\_buffer\_size**, a third request will be required.
+* If negative seek operations are used in `ZipExtFile`, each of them will result in a new request.
 
 ## Alternative modules
 
diff --git a/remotezip.py b/remotezip.py
index b2f133c..f043d61 100644
--- a/remotezip.py
+++ b/remotezip.py
@@ -82,6 +82,7 @@ class RemoteIO(io.IOBase):
         self.position = None
         self._seek_succeeded = False
         self.member_pos2size = None
+        self._last_member_pos = None
 
     def set_pos2size(self, pos2size):
         self.member_pos2size = pos2size
@@ -95,7 +96,15 @@ class RemoteIO(io.IOBase):
                 fetch_size = size
                 stream = False
             else:
-                fetch_size = self.member_pos2size[self.buffer.position]
+                try:
+                    fetch_size = self.member_pos2size[self.buffer.position]
+                    self._last_member_pos = self.buffer.position
+                except KeyError:
+                    if self._last_member_pos and self._last_member_pos < self.buffer.position:
+                        fetch_size = self.member_pos2size[self._last_member_pos]
+                        fetch_size -= (self.buffer.position - self._last_member_pos)
+                    else:
+                        raise OutOfBound("Attempt to seek outside boundary of current zip member")
                 stream = True
 
             self._seek_succeeded = True
@@ -104,6 +113,9 @@ class RemoteIO(io.IOBase):
 
         return self.buffer.read(size)
 
+    def seekable(self):
+        return True
+
     def seek(self, offset, whence=0):
         if whence == 2 and self.file_size is None:
             size = self.initial_buffer_size
diff --git a/setup.py b/setup.py
index 7cc1a7a..b46afa8 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ with open("README.md") as f:
 
 setup(
     name='remotezip',
-    version='0.9.3',
+    version='0.9.4',
     author='Giuseppe Tribulato',
     author_email='gtsystem@gmail.com',
     py_modules=['remotezip'],


Test patch:
diff --git a/test_remotezip.py b/test_remotezip.py
index 68360aa..5bdbdfd 100644
--- a/test_remotezip.py
+++ b/test_remotezip.py
@@ -162,6 +162,17 @@ class TestRemoteIO(unittest.TestCase):
         self.assertEqual(rio.read(4), b'ssss')
         self.assertEqual(rio.buffer.size, 63000)
         self.assertIsNot(rio.buffer, curr_buffer)  # buffer changed
+        curr_buffer = rio.buffer
+
+        # seek forward
+        rio.seek(60354, 0)
+        self.assertEqual(rio.read(4), b'ssss')
+        self.assertIs(rio.buffer, curr_buffer)      # buffer didn't change
+
+        # seek backward
+        rio.seek(51354, 0)
+        self.assertEqual(rio.read(4), b'ssss')
+        self.assertIsNot(rio.buffer, curr_buffer)   # buffer changed
 
         rio.close()