GeezerVison is showing github.com — imaplib 3.14 regression: IMAP4.file became read-only property, breaking subclass overrides (affects imapclient IMAP4_TLS) · Issue #142307 · python/cpython
imaplib 3.14 regression: IMAP4.file became read-only property, breaking subclass overrides (affects imapclient IMAP4_TLS) #142307DescriptionBug report
Bug description:
In Python 3.14, imaplib.IMAP4.file was changed from a normal attribute to a read-only property.
This breaks legitimate subclassing patterns used by third-party libraries such as imapclient, which override open() and assign to self.file.
Example failure
Running imapclient’s IMAP4_TLS on Python 3.14 produces:
AttributeError: property 'file' of 'IMAP4_TLS' object has no setter
Regression cause
In Python 3.14, imaplib.IMAP4.file was changed to:
@property
def file(self):
# The old 'file' attribute is no longer used now that we do our own
# read() and readline() buffering, with which it conflicts.
# As an undocumented interface, it should never have been accessed by
# external code, and therefore does not warrant deprecation.
# Nevertheless, we provide this property for now, to avoid suddenly
# breaking any code in the wild that might have been using it in a
# harmless way.
import warnings
warnings.warn(
'IMAP4.file is unsupported, can cause errors, and may be removed.',
RuntimeWarning,
stacklevel=2)
return self._file
with no setter provided.
https://github.com/python/cpython/blob/3.14/Lib/imaplib.py#L319-L333
Prior to 3.14, file was a normal attribute and writable.
def open(self, host='', port=IMAP4_PORT, timeout=None):
"""Setup connection to remote server on "host:port"
(default: localhost:standard IMAP4 port).
This connection will be used by the routines:
read, readline, send, shutdown.
"""
self.host = host
self.port = port
self.sock = self._create_socket(timeout)
self.file = self.sock.makefile('rb')
https://github.com/python/cpython/blob/3.13/Lib/imaplib.py#L307-L316
Why this is a compatibility break
Even though file was undocumented, turning a previously writable instance attribute into a read-only property introduces a silent backward-incompatible change for:
- Subclasses which override the I/O layer
- SSL/TLS IMAP wrappers such as
imapclient’s IMAP4_TLS
- Any code that monkeypatches or replaces the socket reader
Making file immutable removes the ability to replace the buffered reader the base class uses.
Expected behavior
At minimum, subclass overrides should continue to work.
Options include:
- Add a setter to the property that writes to
_file
- Or rename the internal attribute (e.g., _imaplib_file) instead of shadowing a long-existing public attribute name
- Or provide an explicit API for replacing the buffered input stream
- Or adjust the documentation to specify expected subclass hooks and ensure compatibility
Impact
This change breaks:
imapclient (over 1 million downloads per month)
- Libraries layered on top of
imapclient, including mailsuite and parsedmarc
- All users of IMAP SSL/TLS wrappers relying on custom socket readers
The imapclient maintainers have an open issue tracking this:
mjs/imapclient#618
parsedmarc has an open issue here: domainaware/parsedmarc#636
Request
Please consider restoring backward compatibility by adding a setter or by adjusting the refactor so that subclass assignment to self.file is still possible.
CPython versions tested on:
3.14
Operating systems tested on:
No response
Linked PRs
Reacted by Christoph Nocula Reacted by Jiří Kuneš Activitypicnixz commented on Dec 6, 2025 So I've been trying various approaches and there are few issues:
- While I understand that the package is popular, it's not been updated since 2023 and doesn't officially support Python 3.14.
- Making it a different attribute so that people can do whatever they want with their 'file' is also not a good idea because imapclient uses the super
shutdown() which calls self.file.close(). So if we renamed the attribute, it would become self._imaplib_file.close() and the file created by imapclient would still be opened.
- Making it writable again is annoying because we really don't want to use that attribute actually. If a connection is open, then sock and file are set but need to be synchronized. When opening an SSL connection, we wrap the socket and recreate the file. This is also an issue in our current code where we should have closed the previous file before wrapping the socket. I'm not sure the destructor automatically closes the SocketIO object (that could be annoying!)
I'm inclined to actually not change anything and ask maintainers of imapclient to fix the library. However, I can make it writable again and document that using it is at their own risk. Fixing the synchronization issue is honestly not that interesting either since I prefer removing the attribute altogether in the future so a deprecation is better for Python 3.15. I'll restore the behavior for Python 3.14.
Or rename the internal attribute (e.g., _imaplib_file) instead of shadowing a long-existing public attribute
As per PEP-8, it's not a public attribute. Something that is not documented is not considered part of the public API.
Or adjust the documentation to specify expected subclass hooks and ensure compatibility
The compatibility was never really supported because of the previous file not being closed. seanthegeek commented on Dec 6, 2025 As I read through this whole situation more, yeah. It should really be on the maintainers of imapclient to use an approach that does not use file for something it wasn't intended for. I'm just not sure what that fix would be on their end. Although the repo for that project has shown activity as recently as two months ago, the downstream issue (mjs/imapclient#618 languished without maintainer activity. The ideal situation would be a downstream PR that fixes the issues with Python 3.14+ as-is I'm just not sure what that would be. I appreciate the willingness to revert a change upstream though. seanthegeek commented on Dec 6, 2025 picnixz commented on Dec 6, 2025 Yes but it's better if other users aren't also affected. It's not just one package that may be affected but everyone else. It's also preferrable to entirely remove the attribute in the future if possible. serhiy-storchaka commented on Feb 25, 2026 I do not understand how making the file attribute writeable will help the code that sets the file attribute. They do this for purpose, expecting that this will affect the following I/O, If this is a no-op (since this value is not used), they will be broken in more subtle way. seanthegeek commented on Mar 4, 2026 For what it's worth, imappclient did merge my PR and release it, and there is no reason to access the file attribute writeable again. picnixz commented on Mar 7, 2026 So I closed the corresponding PRs. Considering imapclient is the only consumer I could find in the wild, I think it's fine. OTOH, I think we should instead properly deprecate the attribute as it's currently raising a RuntimeWarning. So I'll open another issue and change the refs in the corresponding PR (that way, the discussion here stays for posterity)
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|