4343from google .cloud import bigquery
4444from google .cloud .bigquery import job
4545from google .cloud .bigquery import table
46- from google .cloud .bigquery .ipython_magics import line_arg_parser as lap
4746from google .cloud .bigquery .ipython_magics import magics
4847from tests .unit .helpers import make_connection
4948from test_utils .imports import maybe_fail_import
@@ -1165,6 +1164,37 @@ def test_bigquery_magic_with_project():
11651164 assert magics .context .project == "general-project"
11661165
11671166
1167+ @pytest .mark .usefixtures ("ipython_interactive" )
1168+ def test_bigquery_magic_with_multiple_options ():
1169+ ip = IPython .get_ipython ()
1170+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1171+ magics .context ._project = None
1172+
1173+ credentials_mock = mock .create_autospec (
1174+ google .auth .credentials .Credentials , instance = True
1175+ )
1176+ default_patch = mock .patch (
1177+ "google.auth.default" , return_value = (credentials_mock , "general-project" )
1178+ )
1179+ run_query_patch = mock .patch (
1180+ "google.cloud.bigquery.ipython_magics.magics._run_query" , autospec = True
1181+ )
1182+ with run_query_patch as run_query_mock , default_patch :
1183+ ip .run_cell_magic (
1184+ "bigquery" ,
1185+ "--project=specific-project --use_legacy_sql --maximum_bytes_billed 1024" ,
1186+ "SELECT 17 as num" ,
1187+ )
1188+
1189+ args , kwargs = run_query_mock .call_args
1190+ client_used = args [0 ]
1191+ assert client_used .project == "specific-project"
1192+
1193+ job_config_used = kwargs ["job_config" ]
1194+ assert job_config_used .use_legacy_sql
1195+ assert job_config_used .maximum_bytes_billed == 1024
1196+
1197+
11681198@pytest .mark .usefixtures ("ipython_interactive" )
11691199@pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
11701200def test_bigquery_magic_with_string_params ():
@@ -1176,7 +1206,9 @@ def test_bigquery_magic_with_string_params():
11761206
11771207 sql = "SELECT @num AS num"
11781208 result = pandas .DataFrame ([17 ], columns = ["num" ])
1179- assert "params_string_df" not in ip .user_ns
1209+
1210+ if "params_dict_df" in ip .user_ns :
1211+ del ip .user_ns ["params_dict_df" ]
11801212
11811213 run_query_patch = mock .patch (
11821214 "google.cloud.bigquery.ipython_magics.magics._run_query" , autospec = True
@@ -1207,9 +1239,13 @@ def test_bigquery_magic_with_dict_params():
12071239 google .auth .credentials .Credentials , instance = True
12081240 )
12091241
1210- sql = "SELECT @num AS num"
1211- result = pandas .DataFrame ([17 ], columns = ["num" ])
1212- assert "params_dict_df" not in ip .user_ns
1242+ sql = "SELECT @num AS num, @tricky_value as tricky_value"
1243+ result = pandas .DataFrame (
1244+ [(17 , '--params "value"' )], columns = ["num" , "tricky_value" ]
1245+ )
1246+
1247+ if "params_dict_df" in ip .user_ns :
1248+ del ip .user_ns ["params_dict_df" ]
12131249
12141250 run_query_patch = mock .patch (
12151251 "google.cloud.bigquery.ipython_magics.magics._run_query" , autospec = True
@@ -1221,7 +1257,7 @@ def test_bigquery_magic_with_dict_params():
12211257 with run_query_patch as run_query_mock :
12221258 run_query_mock .return_value = query_job_mock
12231259
1224- params = {"num" : 17 }
1260+ params = {"num" : 17 , "tricky_value" : '--params "value"' }
12251261 # Insert dictionary into user namespace so that it can be expanded
12261262 ip .user_ns ["params" ] = params
12271263 ip .run_cell_magic ("bigquery" , "params_dict_df --params $params" , sql )
@@ -1233,6 +1269,192 @@ def test_bigquery_magic_with_dict_params():
12331269 assert len (df ) == len (result ) # verify row count
12341270 assert list (df ) == list (result ) # verify column names
12351271
1272+ assert df ["num" ][0 ] == 17
1273+ assert df ["tricky_value" ][0 ] == '--params "value"'
1274+
1275+
1276+ @pytest .mark .usefixtures ("ipython_interactive" )
1277+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1278+ def test_bigquery_magic_with_dict_params_nonexisting ():
1279+ ip = IPython .get_ipython ()
1280+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1281+ magics .context .credentials = mock .create_autospec (
1282+ google .auth .credentials .Credentials , instance = True
1283+ )
1284+
1285+ sql = "SELECT @foo AS foo"
1286+
1287+ with pytest .raises (NameError , match = r".*undefined variable.*unknown_name.*" ):
1288+ ip .run_cell_magic ("bigquery" , "params_dict_df --params $unknown_name" , sql )
1289+
1290+
1291+ @pytest .mark .usefixtures ("ipython_interactive" )
1292+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1293+ def test_bigquery_magic_with_dict_params_incorrect_syntax ():
1294+ ip = IPython .get_ipython ()
1295+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1296+ magics .context .credentials = mock .create_autospec (
1297+ google .auth .credentials .Credentials , instance = True
1298+ )
1299+
1300+ sql = "SELECT @foo AS foo"
1301+
1302+ with pytest .raises (SyntaxError , match = r".*--params.*" ):
1303+ cell_magic_args = "params_dict_df --params {'foo': 1; 'bar': 2}"
1304+ ip .run_cell_magic ("bigquery" , cell_magic_args , sql )
1305+
1306+
1307+ @pytest .mark .usefixtures ("ipython_interactive" )
1308+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1309+ def test_bigquery_magic_with_dict_params_duplicate ():
1310+ ip = IPython .get_ipython ()
1311+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1312+ magics .context .credentials = mock .create_autospec (
1313+ google .auth .credentials .Credentials , instance = True
1314+ )
1315+
1316+ sql = "SELECT @foo AS foo"
1317+
1318+ with pytest .raises (ValueError , match = r"Duplicate --params option\." ):
1319+ cell_magic_args = (
1320+ "params_dict_df --params {'foo': 1} " "--verbose " "--params {'bar': 2} "
1321+ )
1322+ ip .run_cell_magic ("bigquery" , cell_magic_args , sql )
1323+
1324+
1325+ @pytest .mark .usefixtures ("ipython_interactive" )
1326+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1327+ def test_bigquery_magic_with_option_value_incorrect ():
1328+ ip = IPython .get_ipython ()
1329+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1330+ magics .context .credentials = mock .create_autospec (
1331+ google .auth .credentials .Credentials , instance = True
1332+ )
1333+
1334+ sql = "SELECT @foo AS foo"
1335+
1336+ exc_pattern = r".*[Uu]nrecognized input.*option values correct\?.*"
1337+ with pytest .raises (ValueError , match = exc_pattern ):
1338+ cell_magic_args = "params_dict_df --max_results [PLENTY!]"
1339+ ip .run_cell_magic ("bigquery" , cell_magic_args , sql )
1340+
1341+
1342+ @pytest .mark .usefixtures ("ipython_interactive" )
1343+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1344+ def test_bigquery_magic_with_dict_params_negative_value ():
1345+ ip = IPython .get_ipython ()
1346+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1347+ magics .context .credentials = mock .create_autospec (
1348+ google .auth .credentials .Credentials , instance = True
1349+ )
1350+
1351+ sql = "SELECT @num AS num"
1352+ result = pandas .DataFrame ([- 17 ], columns = ["num" ])
1353+
1354+ if "params_dict_df" in ip .user_ns :
1355+ del ip .user_ns ["params_dict_df" ]
1356+
1357+ run_query_patch = mock .patch (
1358+ "google.cloud.bigquery.ipython_magics.magics._run_query" , autospec = True
1359+ )
1360+ query_job_mock = mock .create_autospec (
1361+ google .cloud .bigquery .job .QueryJob , instance = True
1362+ )
1363+ query_job_mock .to_dataframe .return_value = result
1364+ with run_query_patch as run_query_mock :
1365+ run_query_mock .return_value = query_job_mock
1366+
1367+ params = {"num" : - 17 }
1368+ # Insert dictionary into user namespace so that it can be expanded
1369+ ip .user_ns ["params" ] = params
1370+ ip .run_cell_magic ("bigquery" , "params_dict_df --params $params" , sql )
1371+
1372+ run_query_mock .assert_called_once_with (mock .ANY , sql .format (num = - 17 ), mock .ANY )
1373+
1374+ assert "params_dict_df" in ip .user_ns # verify that the variable exists
1375+ df = ip .user_ns ["params_dict_df" ]
1376+ assert len (df ) == len (result ) # verify row count
1377+ assert list (df ) == list (result ) # verify column names
1378+ assert df ["num" ][0 ] == - 17
1379+
1380+
1381+ @pytest .mark .usefixtures ("ipython_interactive" )
1382+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1383+ def test_bigquery_magic_with_dict_params_array_value ():
1384+ ip = IPython .get_ipython ()
1385+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1386+ magics .context .credentials = mock .create_autospec (
1387+ google .auth .credentials .Credentials , instance = True
1388+ )
1389+
1390+ sql = "SELECT @num AS num"
1391+ result = pandas .DataFrame (["foo bar" , "baz quux" ], columns = ["array_data" ])
1392+
1393+ if "params_dict_df" in ip .user_ns :
1394+ del ip .user_ns ["params_dict_df" ]
1395+
1396+ run_query_patch = mock .patch (
1397+ "google.cloud.bigquery.ipython_magics.magics._run_query" , autospec = True
1398+ )
1399+ query_job_mock = mock .create_autospec (
1400+ google .cloud .bigquery .job .QueryJob , instance = True
1401+ )
1402+ query_job_mock .to_dataframe .return_value = result
1403+ with run_query_patch as run_query_mock :
1404+ run_query_mock .return_value = query_job_mock
1405+
1406+ params = {"array_data" : ["foo bar" , "baz quux" ]}
1407+ # Insert dictionary into user namespace so that it can be expanded
1408+ ip .user_ns ["params" ] = params
1409+ ip .run_cell_magic ("bigquery" , "params_dict_df --params $params" , sql )
1410+
1411+ run_query_mock .assert_called_once_with (mock .ANY , sql .format (num = - 17 ), mock .ANY )
1412+
1413+ assert "params_dict_df" in ip .user_ns # verify that the variable exists
1414+ df = ip .user_ns ["params_dict_df" ]
1415+ assert len (df ) == len (result ) # verify row count
1416+ assert list (df ) == list (result ) # verify column names
1417+ assert list (df ["array_data" ]) == ["foo bar" , "baz quux" ]
1418+
1419+
1420+ @pytest .mark .usefixtures ("ipython_interactive" )
1421+ @pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
1422+ def test_bigquery_magic_with_dict_params_tuple_value ():
1423+ ip = IPython .get_ipython ()
1424+ ip .extension_manager .load_extension ("google.cloud.bigquery" )
1425+ magics .context .credentials = mock .create_autospec (
1426+ google .auth .credentials .Credentials , instance = True
1427+ )
1428+
1429+ sql = "SELECT @num AS num"
1430+ result = pandas .DataFrame (["foo bar" , "baz quux" ], columns = ["array_data" ])
1431+
1432+ if "params_dict_df" in ip .user_ns :
1433+ del ip .user_ns ["params_dict_df" ]
1434+
1435+ run_query_patch = mock .patch (
1436+ "google.cloud.bigquery.ipython_magics.magics._run_query" , autospec = True
1437+ )
1438+ query_job_mock = mock .create_autospec (
1439+ google .cloud .bigquery .job .QueryJob , instance = True
1440+ )
1441+ query_job_mock .to_dataframe .return_value = result
1442+ with run_query_patch as run_query_mock :
1443+ run_query_mock .return_value = query_job_mock
1444+
1445+ params = {"array_data" : ("foo bar" , "baz quux" )}
1446+ # Insert dictionary into user namespace so that it can be expanded
1447+ ip .user_ns ["params" ] = params
1448+ ip .run_cell_magic ("bigquery" , "params_dict_df --params $params" , sql )
1449+
1450+ run_query_mock .assert_called_once_with (mock .ANY , sql .format (num = - 17 ), mock .ANY )
1451+
1452+ assert "params_dict_df" in ip .user_ns # verify that the variable exists
1453+ df = ip .user_ns ["params_dict_df" ]
1454+ assert len (df ) == len (result ) # verify row count
1455+ assert list (df ) == list (result ) # verify column names
1456+ assert list (df ["array_data" ]) == ["foo bar" , "baz quux" ]
1457+
12361458
12371459@pytest .mark .usefixtures ("ipython_interactive" )
12381460@pytest .mark .skipif (pandas is None , reason = "Requires `pandas`" )
@@ -1245,7 +1467,7 @@ def test_bigquery_magic_with_improperly_formatted_params():
12451467
12461468 sql = "SELECT @num AS num"
12471469
1248- with pytest .raises (lap . exceptions . QueryParamsParseError ):
1470+ with pytest .raises (SyntaxError ):
12491471 ip .run_cell_magic ("bigquery" , "--params {17}" , sql )
12501472
12511473
0 commit comments