Repository navigation
bpo-15216: TextIOWrapper support change encoding after creation #2343
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
b74d8d6
bpo-15216: TextIOWrapper support set encoding, errors and newline aft…
methane 6213e31
Add note about changing encoding after write
methane 25a8acf
Add NEWS file
methane 8d1ca37
Fix TextIOWrapper.reconfigure(newline=None)
methane 687e18a
Fix _pyio.TextIOWrapper.reconfigure(encoding=...)
methane 24518bc
Don't detect new encoding is alias of old encoding.
methane ef44458
Merge remote-tracking branch 'origin/master' into reconfigure-encoding
methane 4d09f6d
Doc: Explain keyword only arguments are optional
methane 3af545d
test: Add missing assert
methane 78c9cd5
Fix comments and error message
methane b323dcd
prohibit setting newline after first read
methane 1018b67
doc: newline can't be changed after read
methane File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3329,6 +3329,120 @@ def seekable(self): return True | |
| F.tell = lambda x: 0 | ||
| t = self.TextIOWrapper(F(), encoding='utf-8') | ||
|
|
||
| def test_reconfigure_encoding_read(self): | ||
| # latin1 -> utf8 | ||
| # (latin1 can decode utf-8 encoded string) | ||
| data = 'abc\xe9\n'.encode('latin1') + 'd\xe9f\n'.encode('utf8') | ||
| raw = self.BytesIO(data) | ||
| txt = self.TextIOWrapper(raw, encoding='latin1', newline='\n') | ||
| self.assertEqual(txt.readline(), 'abc\xe9\n') | ||
| with self.assertRaises(self.UnsupportedOperation): | ||
| txt.reconfigure(encoding='utf-8') | ||
|
|
||
| def test_reconfigure_write_fromascii(self): | ||
| # ascii has a specific encodefunc in the C implementation, | ||
| # but utf-8-sig has not. Make sure that we get rid of the | ||
| # cached encodefunc when we switch encoders. | ||
| raw = self.BytesIO() | ||
| txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') | ||
| txt.write('foo\n') | ||
| txt.reconfigure(encoding='utf-8-sig') | ||
| txt.write('\xe9\n') | ||
| txt.flush() | ||
| self.assertEqual(raw.getvalue(), b'foo\n\xc3\xa9\n') | ||
|
|
||
| def test_reconfigure_write(self): | ||
| # latin -> utf8 | ||
| raw = self.BytesIO() | ||
| txt = self.TextIOWrapper(raw, encoding='latin1', newline='\n') | ||
| txt.write('abc\xe9\n') | ||
| txt.reconfigure(encoding='utf-8') | ||
| self.assertEqual(raw.getvalue(), b'abc\xe9\n') | ||
| txt.write('d\xe9f\n') | ||
| txt.flush() | ||
| self.assertEqual(raw.getvalue(), b'abc\xe9\nd\xc3\xa9f\n') | ||
|
|
||
| # ascii -> utf-8-sig: ensure that no BOM is written in the middle of | ||
| # the file | ||
| raw = self.BytesIO() | ||
| txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') | ||
| txt.write('abc\n') | ||
| txt.reconfigure(encoding='utf-8-sig') | ||
| txt.write('d\xe9f\n') | ||
| txt.flush() | ||
| self.assertEqual(raw.getvalue(), b'abc\nd\xc3\xa9f\n') | ||
|
|
||
| def test_reconfigure_write_non_seekable(self): | ||
| raw = self.BytesIO() | ||
| raw.seekable = lambda: False | ||
| raw.seek = None | ||
| txt = self.TextIOWrapper(raw, encoding='ascii', newline='\n') | ||
| txt.write('abc\n') | ||
| txt.reconfigure(encoding='utf-8-sig') | ||
| txt.write('d\xe9f\n') | ||
| txt.flush() | ||
|
|
||
| # If the raw stream is not seekable, there'll be a BOM | ||
| self.assertEqual(raw.getvalue(), b'abc\n\xef\xbb\xbfd\xc3\xa9f\n') | ||
|
|
||
| def test_reconfigure_defaults(self): | ||
| txt = self.TextIOWrapper(self.BytesIO(), 'ascii', 'replace', '\n') | ||
| txt.reconfigure(encoding=None) | ||
| self.assertEqual(txt.encoding, 'ascii') | ||
| self.assertEqual(txt.errors, 'replace') | ||
| txt.write('LF\n') | ||
|
|
||
| txt.reconfigure(newline='\r\n') | ||
| self.assertEqual(txt.encoding, 'ascii') | ||
| self.assertEqual(txt.errors, 'replace') | ||
|
|
||
| txt.reconfigure(errors='ignore') | ||
| self.assertEqual(txt.encoding, 'ascii') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why no |
||
| txt.write('CRLF\n') | ||
|
|
||
| txt.reconfigure(encoding='utf-8', newline=None) | ||
| self.assertEqual(txt.errors, 'strict') | ||
| txt.seek(0) | ||
| self.assertEqual(txt.read(), 'LF\nCRLF\n') | ||
|
|
||
| self.assertEqual(txt.detach().getvalue(), b'LF\nCRLF\r\n') | ||
|
|
||
| def test_reconfigure_newline(self): | ||
| raw = self.BytesIO(b'CR\rEOF') | ||
| txt = self.TextIOWrapper(raw, 'ascii', newline='\n') | ||
| txt.reconfigure(newline=None) | ||
| self.assertEqual(txt.readline(), 'CR\n') | ||
| raw = self.BytesIO(b'CR\rEOF') | ||
| txt = self.TextIOWrapper(raw, 'ascii', newline='\n') | ||
| txt.reconfigure(newline='') | ||
| self.assertEqual(txt.readline(), 'CR\r') | ||
| raw = self.BytesIO(b'CR\rLF\nEOF') | ||
| txt = self.TextIOWrapper(raw, 'ascii', newline='\r') | ||
| txt.reconfigure(newline='\n') | ||
| self.assertEqual(txt.readline(), 'CR\rLF\n') | ||
| raw = self.BytesIO(b'LF\nCR\rEOF') | ||
| txt = self.TextIOWrapper(raw, 'ascii', newline='\n') | ||
| txt.reconfigure(newline='\r') | ||
| self.assertEqual(txt.readline(), 'LF\nCR\r') | ||
| raw = self.BytesIO(b'CR\rCRLF\r\nEOF') | ||
| txt = self.TextIOWrapper(raw, 'ascii', newline='\r') | ||
| txt.reconfigure(newline='\r\n') | ||
| self.assertEqual(txt.readline(), 'CR\rCRLF\r\n') | ||
|
|
||
| txt = self.TextIOWrapper(self.BytesIO(), 'ascii', newline='\r') | ||
| txt.reconfigure(newline=None) | ||
| txt.write('linesep\n') | ||
| txt.reconfigure(newline='') | ||
| txt.write('LF\n') | ||
| txt.reconfigure(newline='\n') | ||
| txt.write('LF\n') | ||
| txt.reconfigure(newline='\r') | ||
| txt.write('CR\n') | ||
| txt.reconfigure(newline='\r\n') | ||
| txt.write('CRLF\n') | ||
| expected = 'linesep' + os.linesep + 'LF\nLF\nCR\rCRLF\r\n' | ||
| self.assertEqual(txt.detach().getvalue().decode('ascii'), expected) | ||
|
|
||
|
|
||
| class MemviewBytesIO(io.BytesIO): | ||
| '''A BytesIO object whose read method returns memoryviews | ||
|
|
||
2 changes: 2 additions & 0 deletions
2
Misc/NEWS.d/next/Library/2017-09-16-02-56-33.bpo-15216.lqXCTT.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ``TextIOWrapper.reconfigure()`` supports changing *encoding*, *errors*, and | ||
| *newline*. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature should make it clear that parameters are optional (e.g.
encoding=Noneor whatever the default value is).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default value is just a placeholder to detect "not specified".
It's different between Pure Python implementation and C implementation.
How can I document it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
Nonesupported in both cases? If yes, useNone.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not passing
newlinemeans "keep current newline".On the other hand,
newline=Nonemeans "reset to default newline".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then perhaps
reconfigure(*[, encoding][, errors][, newline][, line_buffering][, write_through])?