@@ -412,10 +412,15 @@ def query_foundry_sql(
412412 Raises:
413413 FoundrySqlQueryFailedError: If the query fails
414414 FoundrySqlQueryClientTimedOutError: If the query times out
415+ TypeError: If an invalid sql_dialect or arrow_compression_codec is provided
416+ ValueError: If an unsupported return_type is provided
415417
416418 """ # noqa: E501
417419 if experimental_use_trino :
418- query = query .replace ("SELECT " , "SELECT /*+ backend(trino) */ " , 1 )
420+ # Case-insensitive replacement of first SELECT keyword
421+ import re
422+
423+ query = re .sub (r"\bSELECT\b" , "SELECT /*+ backend(trino) */" , query , count = 1 , flags = re .IGNORECASE )
419424
420425 response_json = self .api_query (
421426 query = query ,
@@ -428,7 +433,6 @@ def query_foundry_sql(
428433 query_handle = self ._extract_query_handle (response_json )
429434 start_time = time .time ()
430435
431- # Poll for completion
432436 while response_json .get ("status" , {}).get ("type" ) != "ready" :
433437 time .sleep (0.2 )
434438 response = self .api_status (query_handle )
@@ -439,20 +443,14 @@ def query_foundry_sql(
439443 if time .time () > start_time + timeout :
440444 raise FoundrySqlQueryClientTimedOutError (response , timeout = timeout )
441445
442- # Extract tickets from successful response
443446 ticket = self ._extract_ticket (response_json )
444447
445- # Fetch Arrow data using tickets
446448 arrow_stream_reader = self .read_stream_results_arrow (ticket )
447449
448450 if return_type == "pandas" :
449451 return arrow_stream_reader .read_pandas ()
450452
451453 if return_type == "polars" :
452- # The FakeModule implementation used in the _optional packages
453- # throws an ImportError when trying to access attributes of the module.
454- # This ImportError is caught below to fall back to query_foundry_sql_legacy
455- # which will again raise an ImportError when polars is not installed.
456454 from foundry_dev_tools ._optional .polars import pl
457455
458456 arrow_table = arrow_stream_reader .read_all ()
@@ -484,8 +482,26 @@ def _extract_query_handle(self, response_json: dict[str, Any]) -> dict[str, Any]
484482 Returns:
485483 Query handle dict
486484
485+ Raises:
486+ KeyError: If the response JSON doesn't contain the expected structure
487+
487488 """
488- return response_json [response_json ["type" ]]["queryHandle" ]
489+ response_type = response_json .get ("type" )
490+ if not response_type :
491+ msg = f"Response JSON missing 'type' field. Response: { response_json } "
492+ raise KeyError (msg )
493+
494+ type_data = response_json .get (response_type )
495+ if not type_data :
496+ msg = f"Response JSON missing '{ response_type } ' field. Response: { response_json } "
497+ raise KeyError (msg )
498+
499+ query_handle = type_data .get ("queryHandle" )
500+ if not query_handle :
501+ msg = f"Response JSON missing 'queryHandle' in '{ response_type } '. Response: { response_json } "
502+ raise KeyError (msg )
503+
504+ return query_handle
489505
490506 def _extract_ticket (self , response_json : dict [str , Any ]) -> dict [str , Any ]:
491507 """Extract tickets from success response.
@@ -496,16 +512,26 @@ def _extract_ticket(self, response_json: dict[str, Any]) -> dict[str, Any]:
496512 Returns:
497513 List of tickets for fetching results
498514
515+ Raises:
516+ KeyError: If the response JSON doesn't contain the expected structure
517+
499518 """
519+ try :
520+ status = response_json ["status" ]
521+ ready = status ["ready" ]
522+ ticket_groups = ready ["tickets" ]
523+ except KeyError as exc :
524+ msg = (
525+ f"Response JSON missing expected structure. "
526+ f"Expected path: status.ready.tickets. Response: { response_json } "
527+ )
528+ raise KeyError (msg ) from exc
529+
500530 # we combine all tickets into one to get the full data
501531 # if performance is a concern this should be done in parallel
502532 return {
503533 "id" : 0 ,
504- "tickets" : [
505- ticket
506- for ticket_group in response_json ["status" ]["ready" ]["tickets" ]
507- for ticket in ticket_group ["tickets" ]
508- ],
534+ "tickets" : [ticket for ticket_group in ticket_groups for ticket in ticket_group ["tickets" ]],
509535 "type" : "furnace" ,
510536 }
511537
0 commit comments