88from decimal import Decimal
99from enum import Enum
1010from logging import LogRecord
11- from tempfile import TemporaryFile
1211from time import sleep
1312from typing import Any , Optional
1413
3231from soda_core .common .logs import Location , Logs
3332from soda_core .common .soda_cloud_dto import CheckAttribute , CheckAttributes
3433from soda_core .common .statements .metadata_columns_query import ColumnMetadata
35- from soda_core .common .version import SODA_CORE_VERSION , clean_soda_core_version
34+ from soda_core .common .version import SODA_CORE_VERSION
3635from soda_core .common .yaml import SodaCloudYamlSource , YamlObject
3736from soda_core .contracts .contract_publication import ContractPublicationResult
3837from soda_core .contracts .contract_verification import (
@@ -234,10 +233,6 @@ def mark_scan_as_failed(
234233 request_log_name = "mark_scan_as_failed" ,
235234 )
236235
237- def upload_contract_file (self , contract_yaml_source_str : str , soda_cloud_file_path : str ) -> Optional [str ]:
238- logger .debug (f"Sending results to Soda Cloud { Emoticons .CLOUD } " )
239- return self ._upload_scan_yaml_file (yaml_str = contract_yaml_source_str , soda_cloud_file_path = soda_cloud_file_path )
240-
241236 def send_contract_result (self , contract_verification_result : ContractVerificationResult ) -> Optional [dict ]:
242237 """
243238 Returns A scanId string if a 200 OK was received, None otherwise
@@ -276,9 +271,7 @@ def trigger_contract_skeleton_generation(self, dataset_identifier: DatasetIdenti
276271 logger .info (f"{ Emoticons .OK_HAND } Contract skeleton generation triggered on Soda Cloud" )
277272
278273 def send_contract_skeleton (self , contract_yaml_str : str , soda_cloud_file_path : str ) -> None :
279- file_id : Optional [str ] = self ._upload_scan_yaml_file (
280- yaml_str = contract_yaml_str , soda_cloud_file_path = soda_cloud_file_path
281- )
274+ file_id : Optional [str ] = self ._upload_contract_yaml_file (contract_yaml_str )
282275 if file_id :
283276 command_json_dict : dict = {
284277 "type" : "sodaCoreUpsertDraftContract" ,
@@ -293,50 +286,30 @@ def send_contract_skeleton(self, contract_yaml_str: str, soda_cloud_file_path: s
293286
294287 logger .debug (f"Response from Soda Cloud: { response .json ()} " )
295288
296- def _upload_scan_yaml_file (
297- self ,
298- yaml_str : str ,
299- soda_cloud_file_path : str ,
300- ) -> Optional [str ]:
289+ def _upload_contract_yaml_file (self , contract_yaml : str ) -> Optional [str ]:
301290 """
302291 Returns a Soda Cloud fileId or None if something is wrong.
303292 """
304293 try :
305- with TemporaryFile () as temp_file :
306- rows_json_bytes = bytearray (yaml_str , "utf-8" )
307- temp_file .write (rows_json_bytes )
308-
309- file_size_in_bytes = temp_file .tell ()
310- temp_file .seek (0 )
311-
312- headers = {
313- "Authorization" : self ._get_token (),
314- "Content-Type" : "application/yaml" ,
315- "Is-V3" : "true" ,
316- "File-Path" : soda_cloud_file_path ,
317- "Soda-Library-Version" : clean_soda_core_version (),
318- }
319-
320- if file_size_in_bytes == 0 :
321- # because of https://github.com/psf/requests/issues/4215 we can't send content size
322- # when the size is 0 since requests blocks then on I/O indefinitely
323- logger .warning ("Empty file upload detected, not sending Content-Length header" )
324- else :
325- headers ["Content-Length" ] = str (file_size_in_bytes )
326-
327- upload_response = self ._http_post (url = f"{ self .api_url } /scan/upload" , headers = headers , data = temp_file )
328- upload_response_json = upload_response .json ()
329-
330- if isinstance (upload_response_json , dict ) and "fileId" in upload_response_json :
331- return upload_response_json .get ("fileId" )
332- else :
333- logger .critical (f"No fileId received in response: { upload_response_json } " )
334- return None
294+ upload_contract_command : dict = {
295+ "type" : "sodaCoreUploadContractFile" ,
296+ "contents" : contract_yaml ,
297+ }
298+ response : Response = self ._execute_command (
299+ command_json_dict = upload_contract_command , request_log_name = "upload_contract_file"
300+ )
301+ response_json = response .json ()
302+ if isinstance (response_json , dict ) and "fileId" in response_json :
303+ return response_json .get ("fileId" )
304+ else :
305+ logger .critical (f"No fileId received in response: { response_json } " )
306+ return None
335307 except Exception as e :
336308 logger .critical (
337- msg = f"Soda cloud error: Could not upload contract " f" to Soda Cloud: { e } " ,
309+ msg = f"Soda cloud error: Could not upload contract file to Soda Cloud: { e } " ,
338310 exc_info = True ,
339311 )
312+ return None
340313
341314 def test_connection (self ) -> None :
342315 """
@@ -368,12 +341,7 @@ def publish_contract(self, contract_yaml: Optional[ContractYaml]) -> ContractPub
368341 logger .error (f"Skipping contract publication because of insufficient permissions: { reason } " )
369342 return ContractPublicationResult (contract = None )
370343
371- soda_cloud_file_path : str = (
372- contract_local_file_path if isinstance (contract_local_file_path , str ) else "contract.yml"
373- )
374- file_id : Optional [str ] = self ._upload_scan_yaml_file (
375- yaml_str = contract_yaml_str_original , soda_cloud_file_path = soda_cloud_file_path
376- )
344+ file_id : Optional [str ] = self ._upload_contract_yaml_file (contract_yaml_str_original )
377345 if not file_id :
378346 logger .critical ("Uploading the contract file failed" )
379347 return ContractPublicationResult (contract = None )
@@ -382,7 +350,12 @@ def publish_contract(self, contract_yaml: Optional[ContractYaml]) -> ContractPub
382350 "type" : "sodaCorePublishContract" ,
383351 "contract" : {
384352 "fileId" : file_id ,
385- "metadata" : {"source" : {"type" : "local" , "filePath" : contract_local_file_path }},
353+ "metadata" : {
354+ "source" : {
355+ "type" : "local" ,
356+ "filePath" : contract_local_file_path ,
357+ },
358+ },
386359 },
387360 }
388361 response : Response = self ._execute_command (
@@ -509,12 +482,7 @@ def verify_contract_on_agent(
509482 logger .error (f"Skipping contract verification because of insufficient permissions: { reason } " )
510483 return verification_result
511484
512- soda_cloud_file_path : str = (
513- contract_local_file_path if isinstance (contract_local_file_path , str ) else "contract.yml"
514- )
515- file_id : Optional [str ] = self ._upload_scan_yaml_file (
516- yaml_str = contract_yaml_str_original , soda_cloud_file_path = soda_cloud_file_path
517- )
485+ file_id : Optional [str ] = self ._upload_contract_yaml_file (contract_yaml_str_original )
518486 if not file_id :
519487 logger .critical (f"Contract wasn't uploaded so skipping " "sending the results to Soda Cloud" )
520488 return []
@@ -523,7 +491,12 @@ def verify_contract_on_agent(
523491 "type" : "sodaCoreVerifyContract" if publish_results else "sodaCoreTestContract" ,
524492 "contract" : {
525493 "fileId" : file_id ,
526- "metadata" : {"source" : {"type" : "local" , "filePath" : contract_local_file_path }},
494+ "metadata" : {
495+ "source" : {
496+ "type" : "local" ,
497+ "filePath" : contract_local_file_path ,
498+ },
499+ },
527500 },
528501 "verbose" : verbose ,
529502 "variables" : variables ,
0 commit comments