5858
5959if ty .TYPE_CHECKING : # pragma: no cover
6060 import numpy .typing as npt
61+ from typing_extensions import Self # PY310
6162
6263 # Taken from numpy/__init__.pyi
6364 _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
212213 self .order = order
213214 # Flags to keep track of whether a single ImageOpener is created, and
214215 # 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 )
218217 self ._lock = RLock ()
219218
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+
220240 def __del__ (self ):
221241 """If this ``ArrayProxy`` was created with ``keep_file_open=True``,
222242 the open file object is closed if necessary.
@@ -236,13 +256,13 @@ def __setstate__(self, state):
236256 self .__dict__ .update (state )
237257 self ._lock = RLock ()
238258
239- def _should_keep_file_open (self , file_like , keep_file_open ):
259+ def _should_keep_file_open (self , keep_file_open ):
240260 """Called by ``__init__``.
241261
242262 This method determines how to manage ``ImageOpener`` instances,
243263 and the underlying file handles - the behaviour depends on:
244264
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
246266 ``'.gz'`` file, or a path to a non-gzip file.
247267 - whether ``indexed_gzip`` is present (see
248268 :attr:`.openers.HAVE_INDEXED_GZIP`).
@@ -261,24 +281,24 @@ def _should_keep_file_open(self, file_like, keep_file_open):
261281 and closed on each file access.
262282
263283 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
265285 present.
266286
267287 This method returns the values to be used for the internal
268288 ``_persist_opener`` and ``_keep_file_open`` flags; these values are
269289 derived according to the following rules:
270290
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
272292 ``False``.
273293
274294 2. If ``keep_file_open`` (as passed to :meth:``__init__``) is
275295 ``True``, both internal flags are set to ``True``.
276296
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
278298 to a ``.gz`` file or ``indexed_gzip`` is not present, both flags
279299 are set to ``False``.
280300
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
282302 ``.gz`` file, and ``indexed_gzip`` is present, ``_persist_opener``
283303 is set to ``True``, and ``_keep_file_open`` is set to ``False``.
284304 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):
287307 Parameters
288308 ----------
289309
290- file_like : object
291- File-like object or filename, as passed to ``__init__``.
292310 keep_file_open : { True, False }
293311 Flag as passed to ``__init__``.
294312
@@ -311,10 +329,10 @@ def _should_keep_file_open(self, file_like, keep_file_open):
311329 raise ValueError ('keep_file_open must be one of {None, True, False}' )
312330
313331 # 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 ( ):
315333 return False , False
316334 # 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' )
318336
319337 persist_opener = keep_file_open or have_igzip
320338 return keep_file_open , persist_opener
0 commit comments