#26549 closed Bug (wontfix)
HttpResponse.__str__ is missing on Python 3
Reported by: | Robert Rollins | Owned by: | nobody |
---|---|---|---|
Component: | HTTP handling | Version: | 1.9 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The HttpResponse class includes this block:
if six.PY3: __bytes__ = serialize else: __str__ = serialize
Because __str__
is not defined when six.PY3
is True, calling str(response_object)
falls back to __repr__
on Python 3. However, __str__
is defined on Python 2, and it returns the full HTTP message.
It seems like bad idea to have the output of the "convert to string" action be different based on Python version, as it makes multi-version code difficult to implement and debug.
Change History (11)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
I would remove the else
, so that __str__
is defined the same way for both Python2 and Python 3. Heck, the if
isn't even needed, since there's no harm in defining __bytes__
on Python 2, as it won't do anything. So I'd ultimately replace the entire block with
__bytes__ = serialize __str__ = serialize
comment:3 by , 9 years ago
Having a __str__
method on Python 3 which returns bytes might be problematic.
From the Python 3 docs: The return value must be a string object.
comment:4 by , 9 years ago
Ah, *that's* why the if check is there. My inexperience with Python 3 is showing...
Would it be possible to convert the content data in the response to unicode for __str__
? I'm not particularly familiar with Python 3, so I'm not sure if this would be particularly easy.
comment:5 by , 9 years ago
Yes, you just need:
def __str__(self): return bytes(self).decode(self.charset)
I don't think this is a good idea, though, because:
- you aren't supposed to do anything with this value other than show it to a human
- full HTTP responses aren't particularly human friendly
What's the use case here?
comment:6 by , 9 years ago
The place I'm using this is in some tests where I need to check the HTML content of the response. self.assertContains()
isn't sufficient, because that cares about the whitespace, and the templates render a lot of extraneous whitespace. So I use self.assertInHTML()
instead. Unfortunately, assertInHTML()
doesn't accept an HttpResponse object, so I have to send it a string.
Is there a better way to do this with built-in django testing tools?
comment:7 by , 9 years ago
I see. I guess I'd just use content = response.content.decode(response.charset)
.
comment:8 by , 9 years ago
I ended up going with content = str(response.content)
, as that was the only way I found to make the test code compatible with both Python 2 and 3. I think your way probably works for both too, but I'm not really sure. The decode()
and encode()
functions have been the bane of my existence for years, because I never get them right.
comment:9 by , 9 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
comment:10 by , 9 years ago
The decode() and encode() functions have been the bane of my existence for years, because I never get them right.
That's the reason why Python 3 exists... Stop caring about Python 2 now ;-)
What do you think the correct resolution is? The commit where that branch was introduced is e04230e2e406dcf74eeec8d3c95c84362c7da780.