@@ -65,13 +65,40 @@ def detect(cls, item: Union[list, BinaryIO, Path]) -> bool:
65
65
66
66
return False
67
67
68
- @staticmethod
69
- def detect_fh (fh : BinaryIO , original : Union [list , BinaryIO ]) -> bool :
68
+ @classmethod
69
+ def detect_fh (cls , fh : BinaryIO , original : Union [list , BinaryIO ]) -> bool :
70
70
"""Detect if this ``Container`` can be used to open the file-like object ``fh``.
71
71
72
- The function checks wether the raw data contains any magic information that corresponds to this
72
+ The function checks whether the raw data contains any magic information that corresponds to this
73
73
specific container.
74
74
75
+ Args:
76
+ fh: A file-like object that we want to open a ``Container`` on.
77
+ original: The original argument passed to ``detect()``.
78
+
79
+ Returns:
80
+ ``True`` if this ``Container`` can be used for this file-like object, ``False`` otherwise.
81
+ """
82
+ offset = fh .tell ()
83
+ try :
84
+ fh .seek (0 )
85
+ return cls ._detect_fh (fh , original )
86
+ except NotImplementedError :
87
+ raise
88
+ except Exception as e :
89
+ log .warning ("Failed to detect %s container" , cls .__name__ )
90
+ log .debug ("" , exc_info = e )
91
+ finally :
92
+ fh .seek (offset )
93
+
94
+ return False
95
+
96
+ @staticmethod
97
+ def _detect_fh (fh : BinaryIO , original : Union [list , BinaryIO ]) -> bool :
98
+ """Detect if this ``Container`` can be used to open the file-like object ``fh``.
99
+
100
+ This method should be implemented by subclasses. The position of ``fh`` is guaranteed to be ``0``.
101
+
75
102
Args:
76
103
fh: A file-like object that we want to open a ``Container`` on.
77
104
original: The original argument passed to ``detect()``.
@@ -177,6 +204,7 @@ def open(item: Union[list, str, BinaryIO, Path], *args, **kwargs):
177
204
first = item [0 ] if isinstance (item , list ) else item
178
205
first_fh = None
179
206
first_fh_opened = False
207
+ first_fh_offset = None
180
208
first_path = None
181
209
182
210
if hasattr (first , "read" ):
@@ -187,6 +215,10 @@ def open(item: Union[list, str, BinaryIO, Path], *args, **kwargs):
187
215
first_fh = first .open ("rb" )
188
216
first_fh_opened = True
189
217
218
+ if first_fh :
219
+ first_fh_offset = first_fh .tell ()
220
+ first_fh .seek (0 )
221
+
190
222
try :
191
223
for container in CONTAINERS + [RawContainer ]:
192
224
try :
@@ -203,6 +235,8 @@ def open(item: Union[list, str, BinaryIO, Path], *args, **kwargs):
203
235
finally :
204
236
if first_fh_opened :
205
237
first_fh .close ()
238
+ elif first_fh :
239
+ first_fh .seek (first_fh_offset )
206
240
207
241
raise ContainerError (f"Failed to detect container for { item } " )
208
242
0 commit comments