58
58
59
59
if ty .TYPE_CHECKING : # pragma: no cover
60
60
import numpy .typing as npt
61
+ from typing_extensions import Self # PY310
61
62
62
63
# Taken from numpy/__init__.pyi
63
64
_DType = ty .TypeVar ('_DType' , bound = np .dtype [ty .Any ])
@@ -212,11 +213,30 @@ def __init__(self, file_like, spec, *, mmap=True, order=None, keep_file_open=Non
212
213
self .order = order
213
214
# Flags to keep track of whether a single ImageOpener is created, and
214
215
# whether a single underlying file handle is created.
215
- self ._keep_file_open , self ._persist_opener = self ._should_keep_file_open (
216
- file_like , keep_file_open
217
- )
216
+ self ._keep_file_open , self ._persist_opener = self ._should_keep_file_open (keep_file_open )
218
217
self ._lock = RLock ()
219
218
219
+ def _has_fh (self ) -> bool :
220
+ """Determine if our file-like is a filehandle or path"""
221
+ return hasattr (self .file_like , 'read' ) and hasattr (self .file_like , 'seek' )
222
+
223
+ def copy (self ) -> Self :
224
+ """Create a new ArrayProxy for the same file and parameters
225
+
226
+ If the proxied file is an open file handle, the new ArrayProxy
227
+ will share a lock with the old one.
228
+ """
229
+ spec = self ._shape , self ._dtype , self ._offset , self ._slope , self ._inter
230
+ new = self .__class__ (
231
+ self .file_like ,
232
+ spec ,
233
+ mmap = self ._mmap ,
234
+ keep_file_open = self ._keep_file_open ,
235
+ )
236
+ if self ._has_fh ():
237
+ new ._lock = self ._lock
238
+ return new
239
+
220
240
def __del__ (self ):
221
241
"""If this ``ArrayProxy`` was created with ``keep_file_open=True``,
222
242
the open file object is closed if necessary.
@@ -236,13 +256,13 @@ def __setstate__(self, state):
236
256
self .__dict__ .update (state )
237
257
self ._lock = RLock ()
238
258
239
- def _should_keep_file_open (self , file_like , keep_file_open ):
259
+ def _should_keep_file_open (self , keep_file_open ):
240
260
"""Called by ``__init__``.
241
261
242
262
This method determines how to manage ``ImageOpener`` instances,
243
263
and the underlying file handles - the behaviour depends on:
244
264
245
- - whether ``file_like`` is an an open file handle, or a path to a
265
+ - whether ``self. file_like`` is an an open file handle, or a path to a
246
266
``'.gz'`` file, or a path to a non-gzip file.
247
267
- whether ``indexed_gzip`` is present (see
248
268
:attr:`.openers.HAVE_INDEXED_GZIP`).
@@ -261,24 +281,24 @@ def _should_keep_file_open(self, file_like, keep_file_open):
261
281
and closed on each file access.
262
282
263
283
The internal ``_keep_file_open`` flag is only relevant if
264
- ``file_like`` is a ``'.gz'`` file, and the ``indexed_gzip`` library is
284
+ ``self. file_like`` is a ``'.gz'`` file, and the ``indexed_gzip`` library is
265
285
present.
266
286
267
287
This method returns the values to be used for the internal
268
288
``_persist_opener`` and ``_keep_file_open`` flags; these values are
269
289
derived according to the following rules:
270
290
271
- 1. If ``file_like`` is a file(-like) object, both flags are set to
291
+ 1. If ``self. file_like`` is a file(-like) object, both flags are set to
272
292
``False``.
273
293
274
294
2. If ``keep_file_open`` (as passed to :meth:``__init__``) is
275
295
``True``, both internal flags are set to ``True``.
276
296
277
- 3. If ``keep_file_open`` is ``False``, but ``file_like`` is not a path
297
+ 3. If ``keep_file_open`` is ``False``, but ``self. file_like`` is not a path
278
298
to a ``.gz`` file or ``indexed_gzip`` is not present, both flags
279
299
are set to ``False``.
280
300
281
- 4. If ``keep_file_open`` is ``False``, ``file_like`` is a path to a
301
+ 4. If ``keep_file_open`` is ``False``, ``self. file_like`` is a path to a
282
302
``.gz`` file, and ``indexed_gzip`` is present, ``_persist_opener``
283
303
is set to ``True``, and ``_keep_file_open`` is set to ``False``.
284
304
In this case, file handle management is delegated to the
@@ -287,8 +307,6 @@ def _should_keep_file_open(self, file_like, keep_file_open):
287
307
Parameters
288
308
----------
289
309
290
- file_like : object
291
- File-like object or filename, as passed to ``__init__``.
292
310
keep_file_open : { True, False }
293
311
Flag as passed to ``__init__``.
294
312
@@ -311,10 +329,10 @@ def _should_keep_file_open(self, file_like, keep_file_open):
311
329
raise ValueError ('keep_file_open must be one of {None, True, False}' )
312
330
313
331
# file_like is a handle - keep_file_open is irrelevant
314
- if hasattr ( file_like , 'read' ) and hasattr ( file_like , 'seek' ):
332
+ if self . _has_fh ( ):
315
333
return False , False
316
334
# if the file is a gzip file, and we have_indexed_gzip,
317
- have_igzip = openers .HAVE_INDEXED_GZIP and file_like .endswith ('.gz' )
335
+ have_igzip = openers .HAVE_INDEXED_GZIP and self . file_like .endswith ('.gz' )
318
336
319
337
persist_opener = keep_file_open or have_igzip
320
338
return keep_file_open , persist_opener
0 commit comments