Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-90890: New methods to access mailbox.Maildir message info and flags#103905

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
gpshead merged 7 commits intopython:mainfromgildea:mailbox-maildir-get_flags
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletionDoc/library/mailbox.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -424,6 +424,108 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF.
remove the underlying message while the returned file remains open.


.. method:: get_flags(key)

Return as a string the flags that are set on the message
corresponding to *key*.
This is the same as ``get_message(key).get_flags()`` but much
faster, because it does not open the message file.
Use this method when iterating over the keys to determine which
messages are interesting to get.

If you do have a :class:`MaildirMessage` object, use
its :meth:`~MaildirMessage.get_flags` method instead, because
changes made by the message's :meth:`~MaildirMessage.set_flags`,
:meth:`~MaildirMessage.add_flag` and :meth:`~MaildirMessage.remove_flag`
methods are not reflected here until the mailbox's
:meth:`__setitem__` method is called.

.. versionadded:: 3.13


.. method:: set_flags(key, flags)

On the message corresponding to *key*, set the flags specified
by *flags* and unset all others.
Calling ``some_mailbox.set_flags(key, flags)`` is similar to ::

one_message = some_mailbox.get_message(key)
one_message.set_flags(flags)
some_mailbox[key] = one_message

but faster, because it does not open the message file.

If you do have a :class:`MaildirMessage` object, use
its :meth:`~MaildirMessage.set_flags` method instead, because
changes made with this mailbox method will not be visible to the
message object's method, :meth:`~MaildirMessage.get_flags`.

.. versionadded:: 3.13


.. method:: add_flag(key, flag)

On the message corresponding to *key*, set the flags specified
by *flag* without changing other flags. To add more than one
flag at a time, *flag* may be a string of more than one character.

Considerations for using this method versus the message object's
:meth:`~MaildirMessage.add_flag` method are similar to
those for :meth:`set_flags`; see the discussion there.

.. versionadded:: 3.13


.. method:: remove_flag(key, flag)

On the message corresponding to *key*, unset the flags specified
by *flag* without changing other flags. To remove more than one
flag at a time, *flag* may be a string of more than one character.

Considerations for using this method versus the message object's
:meth:`~MaildirMessage.remove_flag` method are similar to
those for :meth:`set_flags`; see the discussion there.

.. versionadded:: 3.13


.. method:: get_info(key)

Return a string containing the info for the message
corresponding to *key*.
This is the same as ``get_message(key).get_info()`` but much
faster, because it does not open the message file.
Use this method when iterating over the keys to determine which
messages are interesting to get.

If you do have a :class:`MaildirMessage` object, use
its :meth:`~MaildirMessage.get_info` method instead, because
changes made by the message's :meth:`~MaildirMessage.set_info` method
are not reflected here until the mailbox's :meth:`__setitem__` method
is called.

.. versionadded:: 3.13


.. method:: set_info(key, info)

Set the info of the message corresponding to *key* to *info*.
Calling ``some_mailbox.set_info(key, flags)`` is similar to ::

one_message = some_mailbox.get_message(key)
one_message.set_info(info)
some_mailbox[key] = one_message

but faster, because it does not open the message file.

If you do have a :class:`MaildirMessage` object, use
its :meth:`~MaildirMessage.set_info` method instead, because
changes made with this mailbox method will not be visible to the
message object's method, :meth:`~MaildirMessage.get_info`.

.. versionadded:: 3.13


.. seealso::

`maildir man page from Courier <https://www.courier-mta.org/maildir.html>`_
Expand DownExpand Up@@ -838,7 +940,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF.
.. note::

A message is typically moved from :file:`new` to :file:`cur` after its
mailbox has been accessed, whether or not the messageishas been
mailbox has been accessed, whether or not the message has been
read. A message ``msg`` has been read if ``"S" in msg.get_flags()`` is
``True``.

Expand Down
50 changes: 50 additions & 0 deletionsLib/mailbox.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -395,6 +395,56 @@ def get_file(self, key):
f = open(os.path.join(self._path, self._lookup(key)), 'rb')
return _ProxyFile(f)

def get_info(self, key):
"""Get the keyed message's "info" as a string."""
subpath = self._lookup(key)
if self.colon in subpath:
return subpath.split(self.colon)[-1]
return ''

def set_info(self, key, info: str):
"""Set the keyed message's "info" string."""
if not isinstance(info, str):
raise TypeError(f'info must be a string: {type(info)}')
old_subpath = self._lookup(key)
new_subpath = old_subpath.split(self.colon)[0]
if info:
new_subpath += self.colon + info
if new_subpath == old_subpath:
return
old_path = os.path.join(self._path, old_subpath)
new_path = os.path.join(self._path, new_subpath)
os.rename(old_path, new_path)
self._toc[key] = new_subpath

def get_flags(self, key):
"""Return as a string the standard flags that are set on the keyed message."""
info = self.get_info(key)
if info.startswith('2,'):
return info[2:]
return ''

def set_flags(self, key, flags: str):
"""Set the given flags and unset all others on the keyed message."""
if not isinstance(flags, str):
raise TypeError(f'flags must be a string: {type(flags)}')
# TODO: check if flags are valid standard flag characters?
self.set_info(key, '2,' + ''.join(sorted(set(flags))))

def add_flag(self, key, flag: str):
"""Set the given flag(s) without changing others on the keyed message."""
if not isinstance(flag, str):
raise TypeError(f'flag must be a string: {type(flag)}')
# TODO: check that flag is a valid standard flag character?
self.set_flags(key, ''.join(set(self.get_flags(key)) | set(flag)))

def remove_flag(self, key, flag: str):
"""Unset the given string flag(s) without changing others on the keyed message."""
if not isinstance(flag, str):
raise TypeError(f'flag must be a string: {type(flag)}')
if self.get_flags(key):
self.set_flags(key, ''.join(set(self.get_flags(key)) - set(flag)))

def iterkeys(self):
"""Return an iterator over keys."""
self._refresh()
Expand Down
86 changes: 86 additions & 0 deletionsLib/test/test_mailbox.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -847,6 +847,92 @@ def test_lock_unlock(self):
self._box.lock()
self._box.unlock()

def test_get_info(self):
# Test getting message info from Maildir, not the message.
msg = mailbox.MaildirMessage(self._template % 0)
key = self._box.add(msg)
self.assertEqual(self._box.get_info(key), '')
msg.set_info('OurTestInfo')
self._box[key] = msg
self.assertEqual(self._box.get_info(key), 'OurTestInfo')

def test_set_info(self):
# Test setting message info from Maildir, not the message.
# This should immediately rename the message file.
msg = mailbox.MaildirMessage(self._template % 0)
key = self._box.add(msg)
def check_info(oldinfo, newinfo):
oldfilename = os.path.join(self._box._path, self._box._lookup(key))
newsubpath = self._box._lookup(key).split(self._box.colon)[0]
if newinfo:
newsubpath += self._box.colon + newinfo
newfilename = os.path.join(self._box._path, newsubpath)
# assert initial conditions
self.assertEqual(self._box.get_info(key), oldinfo)
if not oldinfo:
self.assertNotIn(self._box._lookup(key), self._box.colon)
self.assertTrue(os.path.exists(oldfilename))
if oldinfo != newinfo:
self.assertFalse(os.path.exists(newfilename))
# do the rename
self._box.set_info(key, newinfo)
# assert post conditions
if not newinfo:
self.assertNotIn(self._box._lookup(key), self._box.colon)
if oldinfo != newinfo:
self.assertFalse(os.path.exists(oldfilename))
self.assertTrue(os.path.exists(newfilename))
self.assertEqual(self._box.get_info(key), newinfo)
# none -> has info
check_info('', 'info1')
# has info -> same info
check_info('info1', 'info1')
# has info -> different info
check_info('info1', 'info2')
# has info -> none
check_info('info2', '')
# none -> none
check_info('', '')

def test_get_flags(self):
# Test getting message flags from Maildir, not the message.
msg = mailbox.MaildirMessage(self._template % 0)
key = self._box.add(msg)
self.assertEqual(self._box.get_flags(key), '')
msg.set_flags('T')
self._box[key] = msg
self.assertEqual(self._box.get_flags(key), 'T')

def test_set_flags(self):
msg = mailbox.MaildirMessage(self._template % 0)
key = self._box.add(msg)
self.assertEqual(self._box.get_flags(key), '')
self._box.set_flags(key, 'S')
self.assertEqual(self._box.get_flags(key), 'S')

def test_add_flag(self):
msg = mailbox.MaildirMessage(self._template % 0)
key = self._box.add(msg)
self.assertEqual(self._box.get_flags(key), '')
self._box.add_flag(key, 'B')
self.assertEqual(self._box.get_flags(key), 'B')
self._box.add_flag(key, 'B')
self.assertEqual(self._box.get_flags(key), 'B')
self._box.add_flag(key, 'AC')
self.assertEqual(self._box.get_flags(key), 'ABC')

def test_remove_flag(self):
msg = mailbox.MaildirMessage(self._template % 0)
key = self._box.add(msg)
self._box.set_flags(key, 'abc')
self.assertEqual(self._box.get_flags(key), 'abc')
self._box.remove_flag(key, 'b')
self.assertEqual(self._box.get_flags(key), 'ac')
self._box.remove_flag(key, 'b')
self.assertEqual(self._box.get_flags(key), 'ac')
self._box.remove_flag(key, 'ac')
self.assertEqual(self._box.get_flags(key), '')

def test_folder (self):
# Test for bug #1569790: verify that folders returned by .get_folder()
# use the same factory function.
Expand Down
1 change: 1 addition & 0 deletionsMisc/ACKS
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -630,6 +630,7 @@ Dinu Gherman
Subhendu Ghosh
Jonathan Giddy
Johannes Gijsbers
Stephen Gildea
Michael Gilfix
Julian Gindi
Yannick Gingras
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
New methods :meth:`mailbox.Maildir.get_info`,
:meth:`mailbox.Maildir.set_info`, :meth:`mailbox.Maildir.get_flags`,
:meth:`mailbox.Maildir.set_flags`, :meth:`mailbox.Maildir.add_flag`,
:meth:`mailbox.Maildir.remove_flag`. These methods speed up accessing a
message's info and/or flags and are useful when it is not necessary to
access the message's contents, as when iterating over a Maildir to find
messages with specific flags.

[8]ページ先頭

©2009-2025 Movatter.jp