@@ -584,7 +584,7 @@ def test_bigquery_magic_does_not_clear_display_in_verbose_mode():
584
584
585
585
586
586
@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 ():
588
588
ip = IPython .get_ipython ()
589
589
ip .extension_manager .load_extension ("google.cloud.bigquery" )
590
590
magics .context .credentials = mock .create_autospec (
@@ -1710,6 +1710,143 @@ def test_bigquery_magic_with_improperly_formatted_params():
1710
1710
ip .run_cell_magic ("bigquery" , "--params {17}" , sql )
1711
1711
1712
1712
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
+
1713
1850
@pytest .mark .usefixtures ("ipython_interactive" )
1714
1851
@pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1715
1852
def test_bigquery_magic_with_invalid_multiple_option_values ():
0 commit comments