comparison env/lib/python3.9/site-packages/boltons/mboxutils.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # -*- coding: utf-8 -*-
2 """Useful utilities for working with the `mbox`_-formatted
3 mailboxes. Credit to Mark Williams for these.
4
5 .. _mbox: https://en.wikipedia.org/wiki/Mbox
6 """
7
8 import mailbox
9 import tempfile
10
11
12 DEFAULT_MAXMEM = 4 * 1024 * 1024 # 4MB
13
14
15 class mbox_readonlydir(mailbox.mbox):
16 """A subclass of :class:`mailbox.mbox` suitable for use with mboxs
17 insides a read-only mail directory, e.g., ``/var/mail``. Otherwise
18 the API is exactly the same as the built-in mbox.
19
20 Deletes messages via truncation, in the manner of `Heirloom mailx`_.
21
22 Args:
23 path (str): Path to the mbox file.
24 factory (type): Message type (defaults to :class:`rfc822.Message`)
25 create (bool): Create mailbox if it does not exist. (defaults
26 to ``True``)
27 maxmem (int): Specifies, in bytes, the largest sized mailbox
28 to attempt to copy into memory. Larger mailboxes
29 will be copied incrementally which is more
30 hazardous. (defaults to 4MB)
31
32 .. note::
33
34 Because this truncates and rewrites parts of the mbox file,
35 this class can corrupt your mailbox. Only use this if you know
36 the built-in :class:`mailbox.mbox` does not work for your use
37 case.
38
39 .. _Heirloom mailx: http://heirloom.sourceforge.net/mailx.html
40 """
41 def __init__(self, path, factory=None, create=True, maxmem=1024 * 1024):
42 mailbox.mbox.__init__(self, path, factory, create)
43 self.maxmem = maxmem
44
45 def flush(self):
46 """Write any pending changes to disk. This is called on mailbox
47 close and is usually not called explicitly.
48
49 .. note::
50
51 This deletes messages via truncation. Interruptions may
52 corrupt your mailbox.
53 """
54
55 # Appending and basic assertions are the same as in mailbox.mbox.flush.
56 if not self._pending:
57 if self._pending_sync:
58 # Messages have only been added, so syncing the file
59 # is enough.
60 mailbox._sync_flush(self._file)
61 self._pending_sync = False
62 return
63
64 # In order to be writing anything out at all, self._toc must
65 # already have been generated (and presumably has been modified
66 # by adding or deleting an item).
67 assert self._toc is not None
68
69 # Check length of self._file; if it's changed, some other process
70 # has modified the mailbox since we scanned it.
71 self._file.seek(0, 2)
72 cur_len = self._file.tell()
73 if cur_len != self._file_length:
74 raise mailbox.ExternalClashError('Size of mailbox file changed '
75 '(expected %i, found %i)' %
76 (self._file_length, cur_len))
77
78 self._file.seek(0)
79
80 # Truncation logic begins here. Mostly the same except we
81 # can use tempfile because we're not doing rename(2).
82 with tempfile.TemporaryFile() as new_file:
83 new_toc = {}
84 self._pre_mailbox_hook(new_file)
85 for key in sorted(self._toc.keys()):
86 start, stop = self._toc[key]
87 self._file.seek(start)
88 self._pre_message_hook(new_file)
89 new_start = new_file.tell()
90 while True:
91 buffer = self._file.read(min(4096,
92 stop - self._file.tell()))
93 if buffer == '':
94 break
95 new_file.write(buffer)
96 new_toc[key] = (new_start, new_file.tell())
97 self._post_message_hook(new_file)
98 self._file_length = new_file.tell()
99
100 self._file.seek(0)
101 new_file.seek(0)
102
103 # Copy back our messages
104 if self._file_length <= self.maxmem:
105 self._file.write(new_file.read())
106 else:
107 while True:
108 buffer = new_file.read(4096)
109 if not buffer:
110 break
111 self._file.write(buffer)
112
113 # Delete the rest.
114 self._file.truncate()
115
116 # Same wrap up.
117 self._toc = new_toc
118 self._pending = False
119 self._pending_sync = False
120 if self._locked:
121 mailbox._lock_file(self._file, dotlock=False)