classification
Title: email.policy.Compat32(max_line_length=None) not as documented
Type: behavior Stage: resolved
Components: email Versions: Python 3.7, Python 3.6, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: Mariatta, barry, martin.panter, mcosbuc, r.david.murray
Priority: normal Keywords:

Created on 2017-02-08 10:10 by martin.panter, last changed 2017-06-16 14:21 by Mariatta. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 595 merged mcosbuc, 2017-03-10 11:20
PR 2024 closed matrixise, 2017-06-09 12:18
PR 2025 closed matrixise, 2017-06-09 12:18
PR 2233 merged Mariatta, 2017-06-16 02:07
PR 2234 merged Mariatta, 2017-06-16 02:08
Messages (12)
msg287294 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2017-02-08 10:10
By default, the email package turns single-line header fields into multi-line ones to try and limit the length of each line. The documentation <https://docs.python.org/release/3.5.2/library/email.policy.html#email.policy.Policy.max_line_length> says that setting the policy’s max_line_length attribute to None should prevent line wrapping. But this does not work:

>>> from email.policy import Compat32
>>> from email.message import Message
>>> from email.generator import Generator
>>> from sys import stdout
>>> p = Compat32(max_line_length=None)
>>> m = Message(p)
>>> m["Field"] = "x" * 100
>>> Generator(stdout).flatten(m)  # Field is split across two lines
Field: 
 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

>>> 

A workaround is to specify zero instead:

>>> p = Compat32(max_line_length=0)
>>> Generator(stdout, policy=p).flatten(m)  # All on one line
Field: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Quickly looking at the code, Compat32._fold() passes max_line_length straight to Header.encode(), which is documented as using None as a placeholder for its real default value of 76. So I think the solution would be to add a special case in _fold() to call encode(maxlinelen=0) if max_line_length is None.
msg287310 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-02-08 12:15
That sounds reasonable to me.  Clearly there is a missing test :)
msg289368 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-03-10 14:37
Thanks for the PR.  However, rereading this: since compat32 is providing backward compatibility with the behavior of the python 3.2 email package, we need to check what it would do in this situation before changing the behavior.  What we may need instead is a doc fix, unfortunately :(.  But a test for this is needed either way.
msg289383 - (view) Author: Mircea Cosbuc (mcosbuc) * Date: 2017-03-10 15:53
Thanks for the prompt feedback. In Python 3.2, the closest equivalent for the illustrated issue I could find is:

>>> from email.message import Message
>>> from email.generator import Generator
>>> from sys import stdout
>>> m = Message()
>>> m["Field"] = "x" * 100
>>> g0 = Generator(stdout, maxheaderlen=0)
>>> gn = Generator(stdout, maxheaderlen=None)

>>> g0.flatten(m)
Field: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

>>> gn.flatten(m)
Field: 
 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


It may be the case that a documentation change is all that is needed. I'm not sure that this change would break compatibility since `max_line_length=None` for the policy is not the default value. Please advise further if I should just update the documentation and modify the test to guard for future changes.
msg289385 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-03-10 16:00
So what happens when you do that same operation in 3.5/6 with your change in place?  Does the behavior change?  (I haven't looked back at the code to see if I think it will :)
msg289387 - (view) Author: Mircea Cosbuc (mcosbuc) * Date: 2017-03-10 16:05
Just to be sure, I performed the same operations with my changes in place, there's no change in behaviour. I think it's expected since I only modified how the Compat32 policy passes `max_line_length` to the header class.
msg289421 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-03-10 23:43
OK.  This looks good to me.  I haven't figured out the new commit process, though (like how to do misc news and backports), so I'm not going to be the one to merge it, I'm afraid.  At least not until I do find time to learn.
msg295491 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2017-06-09 06:27
Is the PR ready for merging?
Does this need misc/news entry?

I can help with the backport.
msg295526 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-06-09 12:54
Looks like it just needs a NEWS entry.
msg295748 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2017-06-12 06:43
New changeset b459f7482612d340b88b62edc024628595ec6337 by Mariatta (mircea-cosbuc) in branch 'master':
[email] bpo-29478: Fix passing max_line_length=None from Compat32 policy (GH-595)
https://github.com/python/cpython/commit/b459f7482612d340b88b62edc024628595ec6337
msg296146 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2017-06-16 02:38
New changeset 820b71464c2c0e8cca1abfb5dfe47fa7f7ffec75 by Mariatta in branch '3.5':
[email] bpo-29478: Fix passing max_line_length=None from Compat32 policy (GH-595) (GH-2234)
https://github.com/python/cpython/commit/820b71464c2c0e8cca1abfb5dfe47fa7f7ffec75
msg296194 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2017-06-16 14:19
New changeset e9f4d8db5f30a9603fa0c005382bff78aa1ce232 by Mariatta in branch '3.6':
[email] bpo-29478: Fix passing max_line_length=None from Compat32 policy (GH-595) (GH-2233)
https://github.com/python/cpython/commit/e9f4d8db5f30a9603fa0c005382bff78aa1ce232
History
Date User Action Args
2017-06-16 14:21:56Mariattasetstatus: open -> closed
resolution: fixed
stage: backport needed -> resolved
2017-06-16 14:19:01Mariattasetmessages: + msg296194
2017-06-16 02:38:14Mariattasetmessages: + msg296146
2017-06-16 02:08:48Mariattasetpull_requests: + pull_request2279
2017-06-16 02:07:20Mariattasetpull_requests: + pull_request2278
2017-06-12 06:46:11Mariattasetstage: patch review -> backport needed
2017-06-12 06:43:44Mariattasetmessages: + msg295748
2017-06-09 12:54:51r.david.murraysetmessages: + msg295526
2017-06-09 12:18:47matrixisesetpull_requests: + pull_request2091
2017-06-09 12:18:28matrixisesetpull_requests: + pull_request2090
2017-06-09 06:27:10Mariattasetnosy: + Mariatta

messages: + msg295491
stage: patch review
2017-03-10 23:43:28r.david.murraysetmessages: + msg289421
2017-03-10 16:05:28mcosbucsetmessages: + msg289387
2017-03-10 16:00:48r.david.murraysetmessages: + msg289385
2017-03-10 15:53:07mcosbucsetnosy: + mcosbuc
messages: + msg289383
2017-03-10 14:37:25r.david.murraysetmessages: + msg289368
2017-03-10 11:20:15mcosbucsetpull_requests: + pull_request491
2017-02-08 12:15:00r.david.murraysetmessages: + msg287310
2017-02-08 10:10:45martin.pantercreate