@@ -584,7 +584,7 @@ def test_bigquery_magic_does_not_clear_display_in_verbose_mode():
584584
585585
586586@pytest .mark .usefixtures ("ipython_interactive" )
587- def test_bigquery_magic_clears_display_in_verbose_mode ():
587+ def test_bigquery_magic_clears_display_in_non_verbose_mode ():
588588 ip = IPython .get_ipython ()
589589 ip .extension_manager .load_extension ("google.cloud.bigquery" )
590590 magics .context .credentials = mock .create_autospec (
@@ -1710,6 +1710,143 @@ def test_bigquery_magic_with_improperly_formatted_params():
17101710 ip .run_cell_magic ("bigquery" , "--params {17}" , sql )
17111711
17121712
1713+ @pytest .mark .parametrize (
1714+ "raw_sql" , ("SELECT answer AS 42" , " \t SELECT answer AS 42 \t " )
1715+ )
1716+ @pytest .mark .usefixtures ("ipython_interactive" )
1717+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1718+ def test_bigquery_magic_valid_query_in_existing_variable (ipython_ns_cleanup , raw_sql ):
1719+ ip = IPython .get_ipython ()
1720+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1721+ magics .context .credentials = mock .create_autospec (
1722+ google .auth .credentials .Credentials , instance = True
1723+ )
1724+
1725+ ipython_ns_cleanup .append ((ip , "custom_query" ))
1726+ ipython_ns_cleanup .append ((ip , "query_results_df" ))
1727+
1728+ run_query_patch = mock .patch (
1729+ "google.cloud.bigquery.magics.magics._run_query" , autospec = True
1730+ )
1731+ query_job_mock = mock .create_autospec (
1732+ google .cloud .bigquery .job .QueryJob , instance = True
1733+ )
1734+ mock_result = pandas .DataFrame ([42 ], columns = ["answer" ])
1735+ query_job_mock .to_dataframe .return_value = mock_result
1736+
1737+ ip .user_ns ["custom_query" ] = raw_sql
1738+ cell_body = "$custom_query" # Referring to an existing variable name (custom_query)
1739+ assert "query_results_df" not in ip .user_ns
1740+
1741+ with run_query_patch as run_query_mock :
1742+ run_query_mock .return_value = query_job_mock
1743+
1744+ ip .run_cell_magic ("bigquery" , "query_results_df" , cell_body )
1745+
1746+ run_query_mock .assert_called_once_with (mock .ANY , raw_sql , mock .ANY )
1747+
1748+ assert "query_results_df" in ip .user_ns # verify that the variable exists
1749+ df = ip .user_ns ["query_results_df" ]
1750+ assert len (df ) == len (mock_result ) # verify row count
1751+ assert list (df ) == list (mock_result ) # verify column names
1752+ assert list (df ["answer" ]) == [42 ]
1753+
1754+
1755+ @pytest .mark .usefixtures ("ipython_interactive" )
1756+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1757+ def test_bigquery_magic_nonexisting_query_variable ():
1758+ ip = IPython .get_ipython ()
1759+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1760+ magics .context .credentials = mock .create_autospec (
1761+ google .auth .credentials .Credentials , instance = True
1762+ )
1763+
1764+ run_query_patch = mock .patch (
1765+ "google.cloud.bigquery.magics.magics._run_query" , autospec = True
1766+ )
1767+
1768+ ip .user_ns .pop ("custom_query" , None ) # Make sure the variable does NOT exist.
1769+ cell_body = "$custom_query" # Referring to a non-existing variable name.
1770+
1771+ with pytest .raises (
1772+ NameError , match = r".*custom_query does not exist.*"
1773+ ), run_query_patch as run_query_mock :
1774+ ip .run_cell_magic ("bigquery" , "" , cell_body )
1775+
1776+ run_query_mock .assert_not_called ()
1777+
1778+
1779+ @pytest .mark .usefixtures ("ipython_interactive" )
1780+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1781+ def test_bigquery_magic_empty_query_variable_name ():
1782+ ip = IPython .get_ipython ()
1783+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1784+ magics .context .credentials = mock .create_autospec (
1785+ google .auth .credentials .Credentials , instance = True
1786+ )
1787+
1788+ run_query_patch = mock .patch (
1789+ "google.cloud.bigquery.magics.magics._run_query" , autospec = True
1790+ )
1791+ cell_body = "$" # Not referring to any variable (name omitted).
1792+
1793+ with pytest .raises (
1794+ NameError , match = r"(?i).*missing query variable name.*"
1795+ ), run_query_patch as run_query_mock :
1796+ ip .run_cell_magic ("bigquery" , "" , cell_body )
1797+
1798+ run_query_mock .assert_not_called ()
1799+
1800+
1801+ @pytest .mark .usefixtures ("ipython_interactive" )
1802+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1803+ def test_bigquery_magic_query_variable_non_string (ipython_ns_cleanup ):
1804+ ip = IPython .get_ipython ()
1805+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1806+ magics .context .credentials = mock .create_autospec (
1807+ google .auth .credentials .Credentials , instance = True
1808+ )
1809+
1810+ run_query_patch = mock .patch (
1811+ "google.cloud.bigquery.magics.magics._run_query" , autospec = True
1812+ )
1813+
1814+ ipython_ns_cleanup .append ((ip , "custom_query" ))
1815+
1816+ ip .user_ns ["custom_query" ] = object ()
1817+ cell_body = "$custom_query" # Referring to a non-string variable.
1818+
1819+ with pytest .raises (
1820+ TypeError , match = r".*must be a string or a bytes-like.*"
1821+ ), run_query_patch as run_query_mock :
1822+ ip .run_cell_magic ("bigquery" , "" , cell_body )
1823+
1824+ run_query_mock .assert_not_called ()
1825+
1826+
1827+ @pytest .mark .usefixtures ("ipython_interactive" )
1828+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1829+ def test_bigquery_magic_query_variable_not_identifier ():
1830+ ip = IPython .get_ipython ()
1831+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1832+ magics .context .credentials = mock .create_autospec (
1833+ google .auth .credentials .Credentials , instance = True
1834+ )
1835+
1836+ cell_body = "$123foo" # 123foo is not valid Python identifier
1837+
1838+ with io .capture_output () as captured_io :
1839+ ip .run_cell_magic ("bigquery" , "" , cell_body )
1840+
1841+ # If "$" prefixes a string that is not a Python identifier, we do not treat such
1842+ # cell_body as a variable reference and just treat is as any other cell body input.
1843+ # If at the same time the cell body does not contain any whitespace, it is
1844+ # considered a table name, thus we expect an error that the table ID is not valid.
1845+ output = captured_io .stderr
1846+ assert "ERROR:" in output
1847+ assert "must be a fully-qualified ID" in output
1848+
1849+
17131850@pytest .mark .usefixtures ("ipython_interactive" )
17141851@pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
17151852def test_bigquery_magic_with_invalid_multiple_option_values ():
0 commit comments