diff --git a/.flake8 b/.flake8 index 3d4715b0..e9589b0c 100644 --- a/.flake8 +++ b/.flake8 @@ -8,3 +8,6 @@ exclude = build import-order-style = google max-line-length = 90 + +per-file-ignores = + tests/test_client.py: E501 W291 diff --git a/pydruid/client.py b/pydruid/client.py index ae51eab7..82ba1508 100755 --- a/pydruid/client.py +++ b/pydruid/client.py @@ -556,6 +556,9 @@ def _post(self, query): if e.code == 500: # has Druid returned an error? try: + if isinstance(err, bytes): + # Decode the error before serialize it to JSON + err = err.decode("utf-8") err = json.loads(err) except ValueError: if HTML_ERROR.search(err): diff --git a/tests/test_client.py b/tests/test_client.py index 440a9204..1e16cd7f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,7 +1,7 @@ # -*- coding: UTF-8 -*- import textwrap import urllib -from io import StringIO +from io import BytesIO, StringIO from unittest.mock import Mock, patch import pytest @@ -22,7 +22,10 @@ def create_blank_query(): def _http_error(code, msg, data=""): # Need a file-like object for the response data - fp = StringIO(data) + if isinstance(data, bytes): + fp = BytesIO(data) + else: + fp = StringIO(data) return urllib.error.HTTPError( url="http://fakeurl:8080/druid/v2/", hdrs={}, code=code, msg=msg, fp=fp ) @@ -119,6 +122,29 @@ def test_druid_returns_html_error(self, mock_urlopen): ).strip() ) + @patch("pydruid.client.urllib.request.urlopen") + def test_druid_returns_string_error_bytes_error_response(self, mock_urlopen): + # given + message = b"Error as bytes, please decode me" + mock_urlopen.side_effect = _http_error(500, "Internal Server Error", message) + client = create_client() + + # when / then + with pytest.raises(IOError) as e: + client.topn( + datasource="testdatasource", + granularity="all", + intervals="2015-12-29/pt1h", + aggregations={"count": doublesum("count")}, + dimension="user_name", + metric="count", + filter=Dimension("user_lang") == "en", + threshold=1, + context={"timeout": 1000}, + ) + + assert "Error as bytes, please decode me" in str(e.value) + @patch("pydruid.client.urllib.request.urlopen") def test_druid_returns_results(self, mock_urlopen): # given @@ -185,7 +211,8 @@ def test_client_allows_to_export_last_query(self, mock_urlopen): ) # when / then - # assert that last_query.export_tsv method was called (it should throw an exception, given empty path) + # assert that last_query.export_tsv method was called (it should throw + # an exception, given empty path) with pytest.raises(TypeError): client.export_tsv(None)