]> arthur.barton.de Git - bup.git/blob - lib/bup/io.py
Detect failures to explicitly close mmaps in py3 too
[bup.git] / lib / bup / io.py
1
2 from __future__ import absolute_import, print_function
3 import mmap as py_mmap
4
5 from bup import compat
6 from bup.compat import pending_raise
7
8
9 if compat.py_maj > 2:
10     def byte_stream(file):
11         return file.buffer
12
13     def path_msg(x):
14         """Return a string representation of a path."""
15         # FIXME: configurability (might git-config quotePath be involved?)
16         return x.decode(errors='backslashreplace')
17 else:
18     def byte_stream(file):
19         return file
20
21     def path_msg(x):
22         """Return a string representation of a path."""
23         # FIXME: configurability (might git-config quotePath be involved?)
24         return x
25
26
27 assert not hasattr(py_mmap.mmap, '__del__')
28 if hasattr(py_mmap.mmap, '__enter__'):
29     assert hasattr(py_mmap.mmap, '__exit__')
30
31 class mmap(py_mmap.mmap):
32     '''mmap.mmap wrapper that detects and complains about any instances
33     that aren't explicitly closed.
34
35     '''
36
37     def __init__(self, *args, **kwargs):
38         self._bup_closed = True
39         # Silence deprecation warnings.  mmap's current parent is
40         # object, which accepts no params and as of at least 2.7
41         # warns about them.
42         if py_mmap.mmap.__init__ is not object.__init__:
43             super(mmap, self).__init__(self, *args, **kwargs)
44         self._bup_closed = False
45
46     def close(self):
47         self._bup_closed = True
48         super(mmap, self).close()
49
50     if hasattr(py_mmap.mmap, '__enter__'):
51         def __enter__(self):
52             super(mmap, self).__enter__()
53             return self
54         def __exit__(self, type, value, traceback):
55             # Don't call self.close() when the parent has its own __exit__;
56             # defer to it.
57             self._bup_closed = True
58             result = super(mmap, self).__exit__(type, value, traceback)
59             return result
60     else:
61         def __enter__(self):
62             return self
63         def __exit__(self, type, value, traceback):
64             with pending_raise(value, rethrow=False):
65                 self.close()
66
67     def __del__(self):
68         assert self._bup_closed