@@ -14,7 +14,7 @@ class S3Client:
1414 Takes as input the name of the S3 bucket and resource to be fetched/set.
1515 """
1616
17- def __init__ (self , bucket , resource ):
17+ def __init__ (self , bucket , resource = None ):
1818 self .logger = create_log ('s3_client' )
1919 self .bucket = bucket
2020 self .resource = resource
@@ -23,49 +23,68 @@ def __init__(self, bucket, resource):
2323 self .s3_client = boto3 .client (
2424 's3' , region_name = os .environ .get ('AWS_REGION' , 'us-east-1' ))
2525 except ClientError as e :
26- self .logger .error (
27- 'Could not create S3 client: {err}' .format (err = e ))
28- raise S3ClientError (
29- 'Could not create S3 client: {err}' .format (err = e )) from None
26+ error_msg = f'Could not create S3 client: { e } '
27+ self .logger .error (error_msg )
28+ raise S3ClientError (error_msg ) from None
3029
3130 def close (self ):
3231 self .s3_client .close ()
3332
3433 def fetch_cache (self ):
3534 """Fetches a JSON file from S3 and returns the resulting dictionary"""
36- self .logger .info ('Fetching {file} from S3 bucket {bucket}' . format (
37- file = self .resource , bucket = self .bucket ) )
35+ self .logger .info (
36+ f'Fetching { self .resource } from S3 bucket { self .bucket } ' )
3837 try :
3938 output_stream = BytesIO ()
4039 self .s3_client .download_fileobj (
4140 self .bucket , self .resource , output_stream )
4241 return json .loads (output_stream .getvalue ())
4342 except ClientError as e :
44- self .logger .error (
45- 'Error retrieving {file} from S3 bucket {bucket}: {error}'
46- .format (file = self .resource , bucket = self .bucket , error = e ))
47- raise S3ClientError (
48- 'Error retrieving {file} from S3 bucket {bucket}: {error}'
49- .format (file = self .resource , bucket = self .bucket , error = e )
50- ) from None
43+ error_msg = (
44+ f'Error retrieving { self .resource } from S3 bucket '
45+ f'{ self .bucket } : { e } ' )
46+ self .logger .error (error_msg )
47+ raise S3ClientError (error_msg ) from None
5148
5249 def set_cache (self , state ):
5350 """Writes a dictionary to JSON and uploads the resulting file to S3"""
5451 self .logger .info (
55- 'Setting {file} in S3 bucket {bucket} to {state}' .format (
56- file = self .resource , bucket = self .bucket , state = state ))
52+ f'Setting { self .resource } in S3 bucket { self .bucket } to { state } ' )
5753 try :
5854 input_stream = BytesIO (json .dumps (state ).encode ())
5955 self .s3_client .upload_fileobj (
6056 input_stream , self .bucket , self .resource )
6157 except ClientError as e :
62- self .logger .error (
63- 'Error uploading {file} to S3 bucket {bucket}: {error}'
64- .format (file = self .resource , bucket = self .bucket , error = e ))
65- raise S3ClientError (
66- 'Error uploading {file} to S3 bucket {bucket}: {error}'
67- .format (file = self .resource , bucket = self .bucket , error = e )
68- ) from None
58+ error_msg = (
59+ f'Error uploading { self .resource } to S3 bucket '
60+ f'{ self .s3_bucket } : { e } ' )
61+ self .logger .error (error_msg )
62+ raise S3ClientError (error_msg ) from None
63+
64+ def upload_file (self , content , file_path ):
65+ """
66+ Writes an arbitrary file to S3. Note that this will overwrite any
67+ existing file with the same name.
68+
69+ Parameters
70+ ----------
71+ content: str
72+ The string that should be written to the file. Must be utf-8.
73+ file_path: str
74+ The full path of the file that should be written not including the
75+ bucket. Example: "subdirectory/example_file.csv"
76+ """
77+ self .logger .info (
78+ f'Writing { file_path } in S3 bucket { self .s3_client .name } ' )
79+ try :
80+ input_stream = BytesIO (content .encode ())
81+ self .s3_client .upload_fileobj (input_stream , self .bucket , file_path )
82+ except ClientError as e :
83+ error_msg = (
84+ f'Error uploading { file_path } to S3 bucket '
85+ f'{ self .s3_bucket } : { e } ' )
86+ self .logger .error (error_msg )
87+ raise S3ClientError (error_msg ) from None
6988
7089
7190class S3ClientError (Exception ):
0 commit comments