boto3-assist 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
boto3_assist/s3/s3.py CHANGED
@@ -89,7 +89,7 @@ class S3(S3Connection):
89
89
  else:
90
90
  meta_data.update(local_meta)
91
91
 
92
- object_key = key_path
92
+ key = key_path
93
93
  method_type = method_type.upper()
94
94
 
95
95
  signed_url: str | Dict[str, Any]
@@ -98,7 +98,7 @@ class S3(S3Connection):
98
98
  "put_object",
99
99
  Params={
100
100
  "Bucket": f"{bucket_name}",
101
- "Key": f"{object_key}",
101
+ "Key": f"{key}",
102
102
  # NOTE: if you include the ContentType or Metadata then its required in the when they upload the file
103
103
  # Otherwise you will get a `SignatureDoesNotMatch` error
104
104
  # for now I'm commenting it out.
@@ -111,7 +111,7 @@ class S3(S3Connection):
111
111
  elif method_type == "POST":
112
112
  signed_url = self.client.generate_presigned_post(
113
113
  bucket_name,
114
- object_key,
114
+ key,
115
115
  ExpiresIn=expiration, # URL is valid for x seconds
116
116
  )
117
117
  elif method_type == "GET":
@@ -119,7 +119,7 @@ class S3(S3Connection):
119
119
  "get_object",
120
120
  Params={
121
121
  "Bucket": f"{bucket_name}",
122
- "Key": f"{object_key}",
122
+ "Key": f"{key}",
123
123
  },
124
124
  ExpiresIn=expiration, # URL is valid for x seconds
125
125
  )
@@ -133,12 +133,47 @@ class S3(S3Connection):
133
133
 
134
134
  response = {
135
135
  "signed_url": signed_url,
136
- "object_key": object_key,
136
+ "key": key,
137
137
  "meta_data": meta_data,
138
138
  }
139
139
 
140
140
  return response
141
141
 
142
+ def upload_file_obj(self, bucket: str, key: str, file_obj: bytes | str) -> str:
143
+ """
144
+ Uploads a file object to s3. Returns the full s3 path s3://<bucket>/<key>
145
+ """
146
+
147
+ if key.startswith("/"):
148
+ # remove the first slash
149
+ key = key[1:]
150
+
151
+ logger.debug(
152
+ {
153
+ "metric_filter": "upload_file_to_s3",
154
+ "bucket": bucket,
155
+ "key": key,
156
+ }
157
+ )
158
+ try:
159
+ # convert if necessary
160
+ file_obj: bytes = (
161
+ file_obj.encode("utf-8") if isinstance(file_obj, str) else file_obj
162
+ )
163
+ self.client.upload_fileobj(Fileobj=file_obj, Bucket=bucket, Key=key)
164
+
165
+ except ClientError as ce:
166
+ error = {
167
+ "metric_filter": "upload_file_to_s3_failure",
168
+ "s3 upload": "failure",
169
+ "bucket": bucket,
170
+ "key": key,
171
+ }
172
+ logger.error(error)
173
+ raise RuntimeError(error) from ce
174
+
175
+ return f"s3://{bucket}/{key}"
176
+
142
177
  def upload_file(
143
178
  self,
144
179
  bucket: str,
@@ -188,7 +223,7 @@ class S3(S3Connection):
188
223
  def download_file(
189
224
  self,
190
225
  bucket: str,
191
- object_key: str,
226
+ key: str,
192
227
  local_directory: str | None = None,
193
228
  local_file_path: str | None = None,
194
229
  retry_attempts: int = 3,
@@ -205,7 +240,7 @@ class S3(S3Connection):
205
240
  try:
206
241
  path = self.download_file_no_retries(
207
242
  bucket=bucket,
208
- object_key=object_key,
243
+ key=key,
209
244
  local_directory=local_directory,
210
245
  local_file_path=local_file_path,
211
246
  )
@@ -246,7 +281,7 @@ class S3(S3Connection):
246
281
  def download_file_no_retries(
247
282
  self,
248
283
  bucket: str,
249
- object_key: str,
284
+ key: str,
250
285
  local_directory: str | None = None,
251
286
  local_file_path: str | None = None,
252
287
  ) -> str:
@@ -255,7 +290,7 @@ class S3(S3Connection):
255
290
 
256
291
  Args:
257
292
  bucket (str): s3 bucket
258
- object_key (str): the s3 object key
293
+ key (str): the s3 object key
259
294
  local_directory (str, optional): Local directory to download to. Defaults to None.
260
295
  If None, we'll use a local tmp directory.
261
296
 
@@ -272,13 +307,11 @@ class S3(S3Connection):
272
307
  {
273
308
  "action": "downloading file",
274
309
  "bucket": bucket,
275
- "object_key": object_key,
310
+ "key": key,
276
311
  "local_directory": local_directory,
277
312
  }
278
313
  )
279
- return self.__download_file(
280
- bucket, object_key, local_directory, local_file_path
281
- )
314
+ return self.__download_file(bucket, key, local_directory, local_file_path)
282
315
  except FileNotFoundError:
283
316
  logger.warning(
284
317
  {
@@ -286,12 +319,12 @@ class S3(S3Connection):
286
319
  "error": "FileNotFoundError",
287
320
  "message": "attempting to find it decoded",
288
321
  "bucket": bucket,
289
- "object_key": object_key,
322
+ "key": key,
290
323
  }
291
324
  )
292
325
 
293
- # attempt to decode the object_key
294
- decoded_object_key = HttpUtility.decode_url(object_key)
326
+ # attempt to decode the key
327
+ decoded_object_key = HttpUtility.decode_url(key)
295
328
 
296
329
  logger.error(
297
330
  {
@@ -299,7 +332,7 @@ class S3(S3Connection):
299
332
  "error": "FileNotFoundError",
300
333
  "message": "attempting to find it decoded",
301
334
  "bucket": bucket,
302
- "object_key": object_key,
335
+ "key": key,
303
336
  "decoded_object_key": decoded_object_key,
304
337
  }
305
338
  )
@@ -317,7 +350,7 @@ class S3(S3Connection):
317
350
  )
318
351
  raise e
319
352
 
320
- def stream_file(self, bucket_name: str, object_key: str) -> Dict[str, Any]:
353
+ def stream_file(self, bucket_name: str, key: str) -> Dict[str, Any]:
321
354
  """
322
355
  Gets a file from s3 and returns the response.
323
356
  The "Body" is a streaming body object. You can read it like a file.
@@ -334,7 +367,7 @@ class S3(S3Connection):
334
367
  "source": "download_file",
335
368
  "action": "downloading a file from s3",
336
369
  "bucket": bucket_name,
337
- "key": object_key,
370
+ "key": key,
338
371
  }
339
372
  )
340
373
 
@@ -342,7 +375,7 @@ class S3(S3Connection):
342
375
  error = None
343
376
 
344
377
  try:
345
- response = dict(self.client.get_object(Bucket=bucket_name, Key=object_key))
378
+ response = dict(self.client.get_object(Bucket=bucket_name, Key=key))
346
379
 
347
380
  logger.debug(
348
381
  {"metric_filter": "s3_download_response", "response": str(response)}
@@ -356,7 +389,7 @@ class S3(S3Connection):
356
389
  "metric_filter": "s3_download_error",
357
390
  "error": str(e),
358
391
  "bucket": bucket_name,
359
- "key": object_key,
392
+ "key": key,
360
393
  }
361
394
  ) from e
362
395
 
@@ -366,7 +399,7 @@ class S3(S3Connection):
366
399
  "source": "download_file",
367
400
  "action": "downloading a file from s3",
368
401
  "bucket": bucket_name,
369
- "key": object_key,
402
+ "key": key,
370
403
  "response": response,
371
404
  "errors": error,
372
405
  }
@@ -474,3 +507,19 @@ class S3(S3Connection):
474
507
  else:
475
508
  # Not in AWS Lambda, use the system's default temp directory
476
509
  return tempfile.gettempdir()
510
+
511
+ def encode(
512
+ self, text: str, encoding: str = "utf-8", errors: str = "strict"
513
+ ) -> bytes:
514
+ """
515
+ Encodes a string for s3
516
+ """
517
+ return text.encode(encoding=encoding, errors=errors)
518
+
519
+ def decode(
520
+ self, file_obj: bytes, encoding: str = "utf-8", errors: str = "strict"
521
+ ) -> str:
522
+ """
523
+ Decodes bytes to a string
524
+ """
525
+ return file_obj.decode(encoding=encoding, errors=errors)
boto3_assist/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.2.1'
1
+ __version__ = '0.2.3'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: boto3_assist
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Additional boto3 wrappers to make your life a little easier
5
5
  Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
6
  Classifier: License :: Other/Proprietary License
@@ -2,7 +2,7 @@ boto3_assist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  boto3_assist/boto3session.py,sha256=NWhWtYR3143thEbTpoklkwdz77-fTMs-QsoQdqfRm6E,6430
3
3
  boto3_assist/connection.py,sha256=EJlGueLIYqMSKs7aQlThK1S0Zkb8dOYBWch1iRZdgUI,3233
4
4
  boto3_assist/connection_tracker.py,sha256=_s1t7h2DOi3CCIHIr_HIKyGjku65WR-HJ_v8vJHDvO0,2977
5
- boto3_assist/version.py,sha256=PmcQ2PI2oP8irnLtJLJby2YfW6sBvLAmL-VpABzTqwc,22
5
+ boto3_assist/version.py,sha256=XtWUl6HPylv5jZLd2KkgtPptuzuda93kC2REmOrF-Cs,22
6
6
  boto3_assist/cloudwatch/cloudwatch_connection.py,sha256=mnGWaLSQpHh5EeY7Ek_2o9JKHJxOELIYtQVMX1IaHn4,2480
7
7
  boto3_assist/cloudwatch/cloudwatch_connection_tracker.py,sha256=mzRtO1uHrcfJNh1XrGEiXdTqxwEP8d1RqJkraMNkgK0,410
8
8
  boto3_assist/cloudwatch/cloudwatch_log_connection.py,sha256=qQMZHjUJ6gA8wU9utjQhOURXNSPH2RjxSoAy83bvoCs,1737
@@ -28,7 +28,7 @@ boto3_assist/environment_services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
28
28
  boto3_assist/environment_services/environment_loader.py,sha256=jvG1xwMtgkZqu70NbjG1b1IefKiWgaidjZZoqsSfULk,3370
29
29
  boto3_assist/environment_services/environment_variables.py,sha256=4ccBKdPt6O7hcRT3zBHd8vqu8yQU8udmoD5RLAT3iMs,6801
30
30
  boto3_assist/errors/custom_exceptions.py,sha256=zC2V2Y4PUtKj3uLPn8mB-JessksKWJWvKM9kp1dmvt8,760
31
- boto3_assist/s3/s3.py,sha256=jNT32_dfJMCka5vBRz40l4W4Labh5JJTMMjOGyn0l7Q,15266
31
+ boto3_assist/s3/s3.py,sha256=sIjRMGsrRuQ0NZUP9tnfm_4e_Fx5RSpNKdCu5uToCyI,16592
32
32
  boto3_assist/s3/s3_connection.py,sha256=fMD1FxQazJ9gSFDrRmrv7YJE5QnCesGoWC1b5Dba_Jo,3774
33
33
  boto3_assist/utilities/datetime_utility.py,sha256=TbqGQkJDTahqvaZAIV550nhYnW1Bsq0Hdu3Go6P4RRs,10282
34
34
  boto3_assist/utilities/file_operations.py,sha256=HWQR6o3R5JaISixJS8CpUMsiNgW3Qp5yVZ9KA-jhPmA,3133
@@ -36,8 +36,8 @@ boto3_assist/utilities/http_utility.py,sha256=koFv7Va-8ng-47Nt1K2Sh7Ti95e62IYs9V
36
36
  boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  boto3_assist/utilities/serialization_utility.py,sha256=s_QQRIhtwIE7xN5nU13mNk2wtWyErBX_Sg7n0gbHj-M,4308
38
38
  boto3_assist/utilities/string_utility.py,sha256=w8l063UT3GE48tuJopETyZrjG4CgAzWkyDWMAYMg5Og,7432
39
- boto3_assist-0.2.1.dist-info/METADATA,sha256=_FNgfvN_pjBTPvcqUKouGpaNYtU1tbh6_W6ljkSdPAg,1742
40
- boto3_assist-0.2.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
41
- boto3_assist-0.2.1.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
42
- boto3_assist-0.2.1.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
43
- boto3_assist-0.2.1.dist-info/RECORD,,
39
+ boto3_assist-0.2.3.dist-info/METADATA,sha256=BTWNTK9P2fKTQ-7uQAN3S26ZE2wjZkOHC3QgOfDFu-E,1742
40
+ boto3_assist-0.2.3.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
41
+ boto3_assist-0.2.3.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
42
+ boto3_assist-0.2.3.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
43
+ boto3_assist-0.2.3.dist-info/RECORD,,