Uh oh!
There was an error while loading. Please reload this page.
Fix unicode message in exceptions - #2348
Conversation
dhermes
commented
Sep 19, 2016
@daspecster Ping me when Travis passing? (I'm working on release notes right now so a bit scatterbrained.) |
tseaver
commented
Sep 19, 2016
I'm not in favor of the |
daspecster
commented
Sep 19, 2016
@tseaver ok, can do. |
dhermes
commented
Sep 19, 2016
@daspecster Agree with @tseaver. That won't help detect |
daspecster
commented
Sep 19, 2016
Here's a cleaner way to handle it, however when running the follow test with python 2.7, you get an exception thrown by the exception_test.py fromgoogle.cloudimportexceptionstry:
a=u'That\u2019s all we know'print(a)
raiseexceptions.NotFound(a)
exceptexceptions.GoogleCloudErrorase:
print(e)Output: ╰─$ python test.py
That’s all we know
Traceback (most recent call last):
File "test.py", line 7, in<module>
print(e)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 8: ordinal not in range(128)If that is not something we're concerned with then we are good to go. |
| exception = self._callFUT(response, content) | ||
| self.assertTrue(isinstance(exception, NotFound)) | ||
| self.assertEqual(exception.message, u'That\u2019s all we know.') |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
@daspecster You shouldn't have to branch for from __future__ importprint_functionclassNotFound(Exception):
def__init__(self, message):
super(NotFound, self).__init__(message)
self.message=messageself._errors= ()
def__str__(self):
return'%d %s'% (404, self.message)
VAL=u'it\u2019s all good'print(VAL)
print('='*40)
EXC=NotFound(VAL)
print(EXC)we see the failure NOTE This min-repro was too min. Putting the following in from __future__ importprint_functionprint(u'it\u2019s all good')it works as expected: |
dhermes
commented
Sep 19, 2016
OK, here is the problem: In Python 2, the result of |
I was thinking about Should we used
From the bottom of that link you posted before. |
daspecster
commented
Sep 20, 2016
dhermes
commented
Sep 20, 2016
No. The issue is |
| response = _Response(404) | ||
| content = u'{"error": {"message": "That\u2019s all we know."}}' | ||
| exception = self._callFUT(response, content) | ||
| self.assertTrue(isinstance(exception, NotFound)) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
I'm apparently missing something here. I have the code you demonstrated above, but I'm still getting the error. from __future__ importprint_functionclassNotFound(Exception):
def__init__(self, message):
super(NotFound, self).__init__(message)
self.message=messageself._errors= ()
def__str__(self):
return'%d %s'% (404, self.message)
VAL=u'it\u2019s all good'print(VAL)
print('='*40)
EXC=NotFound(VAL)
print(EXC)╰─$ python2.7 test.py 1 ↵
it’s all good
========================================
Traceback (most recent call last):
File "test.py", line 20, in<module>
print(EXC)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 6: ordinal not in range(128) |
dhermes
commented
Sep 20, 2016
@daspecster The example I posted doesn't fix it, I just posted it because my original snippet was busted. The issue is that Python2.7.12 (default, Jul172016, 01:21:14) [GCC4.8.4] onlinux2Type"help", "copyright", "credits"or"license"formoreinformation.
>>>classA(object):
... def__str__(self):
... returnu'\u2019'
... >>>a=A()
>>>a.__str__()
u'\u2019'>>>str(a)
Traceback (mostrecentcalllast):
File"<stdin>", line1, in<module>UnicodeEncodeError: 'ascii'codeccan't encode character u'\u2019' inposition0: ordinalnotinrange(128)
>>>a.__str__().encode()
Traceback (mostrecentcalllast):
File"<stdin>", line1, in<module>UnicodeEncodeError: 'ascii'codeccan't encode character u'\u2019' inposition0: ordinalnotinrange(128)
>>>unicode(a)
u'\u2019' |
| def __str__(self): | ||
| return '%d %s' % (self.code, self.message) | ||
| return u'%d %s' % (self.code, self.message) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| def test_hit_w_content_as_unicode(self): | ||
| from google.cloud.exceptions import NotFound | ||
| response = _Response(404) | ||
| content = u'{"error": {"message": "%s" }}' % self._EXPECTED_MESSAGE |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| class Test_make_exception(unittest.TestCase): | ||
| _EXPECTED_MESSAGE = u'That\u2019s not found.' |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| def __str__(self): | ||
| return '%d %s' % (self.code, self.message) | ||
| result = u'%d %s' % (self.code, self.message) | ||
| if six.PY2: # pragma: NO COVER Python2 |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| return '%d %s' % (self.code, self.message) | ||
| result = u'%d %s' % (self.code, self.message) | ||
| if six.PY2: | ||
| result = _to_bytes(result) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
daspecster
commented
Sep 21, 2016
@dhermes PTAL when you have a chance. |
| return '%d %s' % (self.code, self.message) | ||
| result = u'%d %s' % (self.code, self.message) | ||
| if six.PY2: | ||
| result = _to_bytes(result) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| return '%d %s' % (self.code, self.message) | ||
| result = u'%d %s' % (self.code, self.message) | ||
| if six.PY2: | ||
| result = result.encode('ascii', 'ignore') |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| import json | ||
| import six | ||
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| if six.PY3: # pragma: NO COVER | ||
| _ERROR_MESSAGE = u'That\u2019s not found.' | ||
| elif six.PY2: # pragma: NO COVER | ||
| _ERROR_MESSAGE = 'Thats not found.' |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
deftest_unicode_non_ascii(self):
value=u'\u2013'# Long hyphenencoded_value=b'\xe2\x80\x93'self.assertRaises(UnicodeEncodeError, self._callFUT, value)
self.assertEqual(self._callFUT(value, encoding='utf-8'),
encoded_value)Also, to get tests for py27 and py35 to pass and cover, I had to check for two message strings. |
dhermes
commented
Sep 21, 2016
Huh? Why should that be necessary? |
| def _to_bytes(value, encoding='ascii'): | ||
| def _to_bytes(value, encoding='utf-8'): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| def test_unicode_non_ascii(self): | ||
| value = u'\u2013' # Long hyphen | ||
| encoded_value = b'\xe2\x80\x93' | ||
| self.assertRaises(UnicodeEncodeError, self._callFUT, value) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| _ERROR_MESSAGE = u'That\'s not found.' | ||
| with _Monkey(six, PY2=False): | ||
| with _Monkey(six, PY3=True): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| from google.cloud.exceptions import NotFound | ||
| _ERROR_MESSAGE = u'That\u2019s not found.' | ||
| _EXPECTED = ('404 That\xe2\x80\x99s not found.', | ||
| '404 %s' % (_ERROR_MESSAGE,)) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
72b29d6 to
8767a4cCompare| import six | ||
| from unit_tests._testing import _Monkey | ||
| from google.cloud.exceptions import NotFound | ||
| _ERROR_MESSAGE = u'That\'s not found.' |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| content = u'{"error": {"message": "%s" }}' % (_ERROR_MESSAGE,) | ||
| exception = self._callFUT(response, content) | ||
| self.assertIn(str(exception), _EXPECTED) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
tseaver
commented
Sep 21, 2016
@daspecster Travis build cancelled. Is there another push coming? |
8767a4c to
9240117Comparedaspecster
commented
Sep 21, 2016
@tseaver yup! Sorry, I was trying to get my commits GPG verified. |
daspecster
commented
Sep 22, 2016
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
) This change can resolve `read_gbq` doctests failures in #2248. Fixes internal issue 417774347🦕
See #2346
@dhermes looking at the magic methods and playing with
__bytes__and__unicode__, the solutions I had felt really hacky. i.e. checking forsix.PY3in__str__and then just callingself.__bytes__()instead.I'm not sure if it's good form to use
__future__here but it seems to be a valid way to solve the issue.