SD / Lib /site-packages /boltons /mboxutils.py
DrFetWartz's picture
Upload folder using huggingface_hub
ffaa9fc
# -*- coding: utf-8 -*-
# Copyright (c) 2013, Mahmoud Hashemi
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * The names of the contributors may not be used to endorse or
# promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Useful utilities for working with the `mbox`_-formatted
mailboxes. Credit to Mark Williams for these.
.. _mbox: https://en.wikipedia.org/wiki/Mbox
"""
import mailbox
import tempfile
DEFAULT_MAXMEM = 4 * 1024 * 1024 # 4MB
class mbox_readonlydir(mailbox.mbox):
"""A subclass of :class:`mailbox.mbox` suitable for use with mboxs
insides a read-only mail directory, e.g., ``/var/mail``. Otherwise
the API is exactly the same as the built-in mbox.
Deletes messages via truncation, in the manner of `Heirloom mailx`_.
Args:
path (str): Path to the mbox file.
factory (type): Message type (defaults to :class:`rfc822.Message`)
create (bool): Create mailbox if it does not exist. (defaults
to ``True``)
maxmem (int): Specifies, in bytes, the largest sized mailbox
to attempt to copy into memory. Larger mailboxes
will be copied incrementally which is more
hazardous. (defaults to 4MB)
.. note::
Because this truncates and rewrites parts of the mbox file,
this class can corrupt your mailbox. Only use this if you know
the built-in :class:`mailbox.mbox` does not work for your use
case.
.. _Heirloom mailx: http://heirloom.sourceforge.net/mailx.html
"""
def __init__(self, path, factory=None, create=True, maxmem=1024 * 1024):
mailbox.mbox.__init__(self, path, factory, create)
self.maxmem = maxmem
def flush(self):
"""Write any pending changes to disk. This is called on mailbox
close and is usually not called explicitly.
.. note::
This deletes messages via truncation. Interruptions may
corrupt your mailbox.
"""
# Appending and basic assertions are the same as in mailbox.mbox.flush.
if not self._pending:
if self._pending_sync:
# Messages have only been added, so syncing the file
# is enough.
mailbox._sync_flush(self._file)
self._pending_sync = False
return
# In order to be writing anything out at all, self._toc must
# already have been generated (and presumably has been modified
# by adding or deleting an item).
assert self._toc is not None
# Check length of self._file; if it's changed, some other process
# has modified the mailbox since we scanned it.
self._file.seek(0, 2)
cur_len = self._file.tell()
if cur_len != self._file_length:
raise mailbox.ExternalClashError('Size of mailbox file changed '
'(expected %i, found %i)' %
(self._file_length, cur_len))
self._file.seek(0)
# Truncation logic begins here. Mostly the same except we
# can use tempfile because we're not doing rename(2).
with tempfile.TemporaryFile() as new_file:
new_toc = {}
self._pre_mailbox_hook(new_file)
for key in sorted(self._toc.keys()):
start, stop = self._toc[key]
self._file.seek(start)
self._pre_message_hook(new_file)
new_start = new_file.tell()
while True:
buffer = self._file.read(min(4096,
stop - self._file.tell()))
if buffer == '':
break
new_file.write(buffer)
new_toc[key] = (new_start, new_file.tell())
self._post_message_hook(new_file)
self._file_length = new_file.tell()
self._file.seek(0)
new_file.seek(0)
# Copy back our messages
if self._file_length <= self.maxmem:
self._file.write(new_file.read())
else:
while True:
buffer = new_file.read(4096)
if not buffer:
break
self._file.write(buffer)
# Delete the rest.
self._file.truncate()
# Same wrap up.
self._toc = new_toc
self._pending = False
self._pending_sync = False
if self._locked:
mailbox._lock_file(self._file, dotlock=False)