From 795502e07d66b5516c24ed1668c6e3afd1f73091 Mon Sep 17 00:00:00 2001 From: Peter Lamut Date: Mon, 29 Jul 2019 18:12:01 +0200 Subject: [PATCH 1/2] Hide error traceback in BigQuery cell magic The traceback is an internal detail of the IPython magic, the users should only see the relevant error information. --- bigquery/google/cloud/bigquery/magics.py | 11 +++++++++- bigquery/tests/unit/test_magics.py | 27 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/bigquery/google/cloud/bigquery/magics.py b/bigquery/google/cloud/bigquery/magics.py index 9bf2019c5c2e..dc2c0f59278a 100644 --- a/bigquery/google/cloud/bigquery/magics.py +++ b/bigquery/google/cloud/bigquery/magics.py @@ -417,11 +417,20 @@ def _cell_magic(line, query): elif args.maximum_bytes_billed is not None: value = int(args.maximum_bytes_billed) job_config.maximum_bytes_billed = value - query_job = _run_query(client, query, job_config) + + error = None + try: + query_job = _run_query(client, query, job_config) + except Exception as ex: + error = str(ex) if not args.verbose: display.clear_output() + if error: + print("\nERROR:\n", error) + return + result = query_job.to_dataframe(bqstorage_client=bqstorage_client) if args.destination_var: IPython.get_ipython().push({args.destination_var: result}) diff --git a/bigquery/tests/unit/test_magics.py b/bigquery/tests/unit/test_magics.py index 44e0571d1ee4..93eeb78f2d4c 100644 --- a/bigquery/tests/unit/test_magics.py +++ b/bigquery/tests/unit/test_magics.py @@ -32,6 +32,7 @@ except ImportError: # pragma: NO COVER IPython = None +from google.api_core import exceptions import google.auth.credentials try: @@ -815,3 +816,29 @@ def test_bigquery_magic_with_improperly_formatted_params(): with pytest.raises(SyntaxError): ip.run_cell_magic("bigquery", "--params {17}", sql) + + +@pytest.mark.usefixtures("ipython_interactive") +def test_bigquery_magic_omits_tracebacks_from_error_message(): + ip = IPython.get_ipython() + ip.extension_manager.load_extension("google.cloud.bigquery") + + credentials_mock = mock.create_autospec( + google.auth.credentials.Credentials, instance=True + ) + default_patch = mock.patch( + "google.auth.default", return_value=(credentials_mock, "general-project") + ) + + run_query_patch = mock.patch( + "google.cloud.bigquery.magics._run_query", + autospec=True, + side_effect=exceptions.BadRequest("Syntax error in SQL query"), + ) + + with run_query_patch, default_patch, io.capture_output() as captured_io: + ip.run_cell_magic("bigquery", "", "SELECT foo FROM WHERE LIMIT bar") + + output = captured_io.stdout + assert "400 Syntax error in SQL query" in output + assert "Traceback (most recent call last)" not in output From 71237531518abc72a55bcc954e4dfcf40930fee0 Mon Sep 17 00:00:00 2001 From: Peter Lamut Date: Wed, 31 Jul 2019 09:39:31 +0200 Subject: [PATCH 2/2] Output BigQuery cell magic error message to stderr --- bigquery/google/cloud/bigquery/magics.py | 3 ++- bigquery/tests/unit/test_magics.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bigquery/google/cloud/bigquery/magics.py b/bigquery/google/cloud/bigquery/magics.py index dc2c0f59278a..2eee7e087f30 100644 --- a/bigquery/google/cloud/bigquery/magics.py +++ b/bigquery/google/cloud/bigquery/magics.py @@ -130,6 +130,7 @@ from __future__ import print_function import ast +import sys import time from concurrent import futures @@ -428,7 +429,7 @@ def _cell_magic(line, query): display.clear_output() if error: - print("\nERROR:\n", error) + print("\nERROR:\n", error, file=sys.stderr) return result = query_job.to_dataframe(bqstorage_client=bqstorage_client) diff --git a/bigquery/tests/unit/test_magics.py b/bigquery/tests/unit/test_magics.py index 93eeb78f2d4c..1a896dda0829 100644 --- a/bigquery/tests/unit/test_magics.py +++ b/bigquery/tests/unit/test_magics.py @@ -839,6 +839,7 @@ def test_bigquery_magic_omits_tracebacks_from_error_message(): with run_query_patch, default_patch, io.capture_output() as captured_io: ip.run_cell_magic("bigquery", "", "SELECT foo FROM WHERE LIMIT bar") - output = captured_io.stdout + output = captured_io.stderr assert "400 Syntax error in SQL query" in output assert "Traceback (most recent call last)" not in output + assert "Syntax error" not in captured_io.stdout