Repository: googleapis/python-bigquery

Issue:
Uninformative Jupyter cell magic error if the query is missing

### Environment details

BigQuery client v1.24.0, all Python versions.

### Steps to reproduce

1. Fire up a Jupyter notebook or an IPython session and load the `bigquery` extension:
    ```
     %load_ext google.cloud.bigquery
    ```

2. Use the `bigquery` cell magic without specifying the query:
    ```
    %%bigquery --project my-project --destination_table my_dataset.my_table
    ```
**Actual result:**
An error message is displayed, but is kind of misleading:
```
ERROR:
 table_id must be a fully-qualified ID in standard SQL format, e.g., "project.dataset.table_id", got 
```
It might make the user wonder why the table ID is incorrect even if `--destination` is correctly specified.

**Expected result:**
The error message should explain that the query is missing in the cell body.

### Proposed solution
The [current implementation](https://github.com/googleapis/python-bigquery/blob/v1.24.0/google/cloud/bigquery/magics.py#L507-L511) assumes that any query without whitespace represents a table ID, but it fails to check if the query is non-empty in the first place. The latter check should be added.


Discussion:

Resolving patch:
diff --git a/google/cloud/bigquery/magics.py b/google/cloud/bigquery/magics.py
--- a/google/cloud/bigquery/magics.py
+++ b/google/cloud/bigquery/magics.py
@@ -66,7 +66,9 @@
           the variable name (ex. ``$my_dict_var``). See ``In[6]`` and ``In[7]``
           in the Examples section below.
     * ``<query>`` (required, cell argument):
-        SQL query to run.
+        SQL query to run. If the query does not contain any whitespace (aside
+        from leading and trailing whitespace), it is assumed to represent a
+        fully-qualified table ID, and the latter's data will be fetched.
 
     Returns:
         A :class:`pandas.DataFrame` with the query results.
@@ -506,6 +508,11 @@ def _cell_magic(line, query):
 
         query = query.strip()
 
+        if not query:
+            error = ValueError("Query is missing.")
+            _handle_error(error, args.destination_var)
+            return
+
         # Any query that does not contain whitespace (aside from leading and trailing whitespace)
         # is assumed to be a table id
         if not re.search(r"\s", query):


Test patch:
diff --git a/tests/unit/test_magics.py b/tests/unit/test_magics.py
--- a/tests/unit/test_magics.py
+++ b/tests/unit/test_magics.py
@@ -800,6 +800,22 @@ def test_bigquery_magic_w_table_id_invalid():
     assert "Traceback (most recent call last)" not in output
 
 
+def test_bigquery_magic_w_missing_query():
+    ip = IPython.get_ipython()
+    ip.extension_manager.load_extension("google.cloud.bigquery")
+    magics.context._project = None
+
+    cell_body = "   \n    \n   \t\t  \n  "
+
+    with io.capture_output() as captured_io:
+        ip.run_cell_magic("bigquery", "df", cell_body)
+
+    output = captured_io.stderr
+    assert "Could not save output to variable" in output
+    assert "Query is missing" in output
+    assert "Traceback (most recent call last)" not in output
+
+
 @pytest.mark.usefixtures("ipython_interactive")
 @pytest.mark.skipif(pandas is None, reason="Requires `pandas`")
 def test_bigquery_magic_w_table_id_and_destination_var():