-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xarray.backends refactor #2261
xarray.backends refactor #2261
Changes from 2 commits
4faaf3a
c82a38c
7a55a30
51463dd
23e132f
8fc8183
422944b
aea0a1a
4366c0b
f35b7e7
057cad2
0f3e656
1a0cc10
8784e6b
83d9b10
a0074ff
062ba96
2d41b29
2adf486
76f151c
769f079
3e97264
5e67efe
8dc77c4
1d38335
6350ca6
4aa0df7
67377c7
8c00f44
2a5d1f0
a6c170b
009e30d
14118ea
c778488
fe14ebf
f1026ce
e13406b
465dfae
55d35c8
c8fbadc
ede8ef0
220c302
36f1156
c6f43dd
8916bc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import contextlib | ||
import threading | ||
|
||
|
||
class FileManager(object): | ||
"""Base class for context managers for managing file objects. | ||
|
||
Unlike files, FileManager objects should be safely. They must be explicitly | ||
closed. | ||
|
||
Example usage: | ||
|
||
import functools | ||
|
||
manager = FileManager(functools.partial(open, filename), mode='w') | ||
with manager.acquire() as f: | ||
f.write(...) | ||
manager.close() | ||
""" | ||
|
||
def __init__(self, opener, mode=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also support There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking of |
||
"""Initialize a FileManager. | ||
|
||
Parameters | ||
---------- | ||
opener : callable | ||
Callable that opens a given file when called, returning a file | ||
object. | ||
mode : str, optional | ||
If provided, passed to opener as a keyword argument. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. W291 trailing whitespace |
||
""" | ||
raise NotImplementedError | ||
|
||
@contextlib.contextmanager | ||
def acquire(self): | ||
"""Context manager for acquiring a file object. | ||
|
||
This method must be thread-safe: it should be safe to simultaneously | ||
acquire a file in multiple threads at the same time (assuming that | ||
the underlying file object is thread-safe). | ||
|
||
Yields | ||
------ | ||
Open file object, as returned by opener(). | ||
""" | ||
raise NotImplementedError | ||
|
||
def close(self): | ||
"""Explicitly close any associated file object (if necessary).""" | ||
raise NotImplementedError | ||
|
||
|
||
_DEFAULT_MODE = object() | ||
|
||
|
||
def _open(opener, mode): | ||
return opener() if mode is _DEFAULT_MODE else opener(mode=mode) | ||
|
||
|
||
class ExplicitFileManager(FileManager): | ||
"""A file manager that holds a file open until explicitly closed. | ||
|
||
This is mostly a reference implementation: must real use cases should use | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. must->most |
||
ExplicitLazyFileContext for better performance. | ||
""" | ||
|
||
def __init__(self, opener, mode=_DEFAULT_MODE): | ||
self._opener = opener | ||
# file has already been created, don't override when restoring | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you expand on this a bit? How do we KNOW that the file has already been created? I'm wondering if the mode switch should go after the file open line. |
||
self._mode = 'a' if mode == 'w' else mode | ||
self._file = _open(opener, mode) | ||
|
||
@contextlib.contextmanager | ||
def acquire(self): | ||
yield self._file | ||
|
||
def close(self): | ||
self._file.close() | ||
|
||
def __getstate__(self): | ||
return {'opener': self._opener, 'mode': self._mode} | ||
|
||
def __setstate__(self, state): | ||
self.__init__(**state) | ||
|
||
|
||
class LazyFileManager(FileManager): | ||
"""An explicit file manager that lazily opens files.""" | ||
|
||
def __init__(self, opener, mode=_DEFAULT_MODE): | ||
self._opener = opener | ||
self._mode = mode | ||
self._lock = threading.Lock() | ||
self._file = None | ||
|
||
@contextlib.contextmanager | ||
def acquire(self): | ||
with self._lock: | ||
if self._file is None: | ||
self._file = _open(self._opener, self._mode) | ||
# file has already been created, don't override when restoring | ||
if self._mode == 'w': | ||
self._mode = 'a' | ||
yield self._file | ||
|
||
def close(self): | ||
if self._file is not None: | ||
self._file.close() | ||
|
||
def __getstate__(self): | ||
return {'opener': self._opener, 'mode': self._mode} | ||
|
||
def __setstate__(self, state): | ||
self.__init__(**state) | ||
|
||
|
||
class AutoclosingFileManager(FileManager): | ||
"""A FileManager that automatically opens/closes files when used.""" | ||
|
||
def __init__(self, opener, mode=_DEFAULT_MODE): | ||
self._opener = opener | ||
self._mode = mode | ||
self._lock = threading.Lock() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thoughts on allowing other locks to be passed in here? Do we need to support the |
||
self._file = None | ||
self._references = 0 | ||
|
||
@contextlib.contextmanager | ||
def acquire(self): | ||
with self._lock: | ||
if self._file is None: | ||
self._file = _open(self._opener, self._mode) | ||
# file has already been created, don't override when restoring | ||
if self._mode == 'w': | ||
self._mode = 'a' | ||
self._references += 1 | ||
|
||
yield self._file | ||
|
||
with self._lock: | ||
self._references -= 1 | ||
if not self._references: | ||
self._file.close() | ||
self._file = None | ||
|
||
def close(self): | ||
pass | ||
|
||
def __getstate__(self): | ||
return {'opener': self._opener, 'mode': self._mode} | ||
|
||
def __setstate__(self, state): | ||
self.__init__(**state) | ||
|
||
|
||
# TODO: write a FileManager that makes use of an LRU cache. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this description is missing a few words.