pyaws-s3 1.0.23__py3-none-any.whl → 1.0.27__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.
pyaws_s3/s3.py CHANGED
@@ -42,6 +42,25 @@ class S3Client:
42
42
  self.region_name = kwargs.get("region_name", os.getenv("AWS_REGION"))
43
43
  self.bucket_name = kwargs.get("bucket_name", os.getenv("AWS_BUCKET_NAME"))
44
44
 
45
+ # crea una funzione per verifica la presenza di un file nel bucket
46
+ def file_exists(self, object_name: str) -> bool:
47
+ """
48
+ Check if a file exists in the S3 bucket.
49
+
50
+ Args:
51
+ object_name (str): The name of the S3 object to check.
52
+
53
+ Returns:
54
+ bool: True if the file exists, False otherwise.
55
+ """
56
+ s3_client = self._get_s3_client()
57
+ try:
58
+ s3_client.head_object(Bucket=self.bucket_name, Key=object_name)
59
+ return True
60
+ except Exception as e:
61
+ logger.error(f"Error checking file existence: {str(e)}")
62
+ return False
63
+
45
64
  def _bytes_from_figure(self, f: Figure, **kwargs) -> bytes:
46
65
  """
47
66
  Convert a Plotly Figure to a PNG image as bytes.
@@ -173,23 +192,24 @@ class S3Client:
173
192
 
174
193
  return temp_url
175
194
 
176
- def upload_bytes(self, *args, **kwargs: Any):
195
+ def upload_bytes(self, *args, **kwargs: Any) -> tuple[str, bool]:
177
196
  """
178
197
  Upload a Plotly Figure as a PNG image to an S3 bucket and generate a pre-signed URL.
179
198
 
180
199
  Args:
181
- fig (Figure): The Plotly Figure object to upload.
182
- bucket_name (str): The name of the S3 bucket.
200
+ bytes_data (bytes): The bytes data of the image to upload.
183
201
  object_name (str): The name of the S3 object.
202
+ format_file (str): Format of the image. Defaults to 'pdf' ["png", "jpeg", "svg", "html", "pdf"].
203
+ overwrite (bool): If True, overwrite the existing file in S3. Defaults to False.
204
+ presigned_url (bool): If True, generate a pre-signed URL for the uploaded image. Defaults to False.
205
+ Raises:
206
+ Exception: If there is an error uploading the image.
184
207
 
185
208
  Keyword Args:
186
209
  format_file (str): Format of the image. Defaults to 'png'.
187
210
 
188
211
  Returns:
189
212
  str: Pre-signed URL for the uploaded image.
190
-
191
- Raises:
192
- Exception: If there is an error uploading the image.
193
213
  """
194
214
  try:
195
215
 
@@ -199,6 +219,9 @@ class S3Client:
199
219
  else:
200
220
  bytes_data = kwargs.get("bytes_data", None)
201
221
  object_name = kwargs.get("object_name", None)
222
+
223
+ overwrite = kwargs.get("overwrite", False)
224
+ presigned_url = kwargs.get("presigned_url", False)
202
225
 
203
226
  if bytes_data is None:
204
227
  raise Exception("Figure is None")
@@ -209,6 +232,16 @@ class S3Client:
209
232
  format_file : FormatFile = kwargs.get("format_file", "pdf")
210
233
  mimetypes = "application/pdf"
211
234
 
235
+ # Get S3 client and resource
236
+ s3_client = self._get_s3_client()
237
+ s3_resource = self._get_s3_resource()
238
+
239
+ if not overwrite and self.file_exists(object_name):
240
+ print(f"File {object_name} already exists in the bucket {self.bucket_name}. Use overwrite=True to overwrite it.")
241
+ if presigned_url:
242
+ return self._create_url(s3_client, self.bucket_name, object_name), False
243
+ return object_name, False
244
+
212
245
  if format_file not in ["png", "jpeg", "svg", "html", "pdf"]:
213
246
  raise Exception("Invalid format_file provided. Supported formats are: png, jpeg, svg, html, pdf")
214
247
  if format_file == "png":
@@ -224,15 +257,13 @@ class S3Client:
224
257
  else:
225
258
  raise Exception("Invalid MIME type provided")
226
259
 
227
- s3_resource = self._get_s3_resource()
228
-
229
260
  s3_resource.Bucket(self.bucket_name).Object(object_name).put(Body=bytes_data, ContentType=mimetypes)
230
-
261
+ return self._create_url(s3_client, self.bucket_name, object_name), True
231
262
  except Exception as e:
232
263
  logger.error(f"Error uploading image: {str(e)}")
233
264
  raise Exception(f"Error uploading image: {str(e)}")
234
265
 
235
- def upload_image(self, *args, **kwargs: Any) -> str:
266
+ def upload_image(self, *args, **kwargs: Any) -> tuple[str, bool]:
236
267
  """
237
268
  Upload a Plotly Figure as a PNG image to an S3 bucket and generate a pre-signed URL.
238
269
 
@@ -240,6 +271,11 @@ class S3Client:
240
271
  fig (Figure): The Plotly Figure object to upload.
241
272
  bucket_name (str): The name of the S3 bucket.
242
273
  object_name (str): The name of the S3 object.
274
+ format_file (str): Format of the image. Defaults to 'png' ["png", "jpeg", "svg", "html"].
275
+ overwrite (bool): If True, overwrite the existing file in S3. Defaults to False.
276
+ presigned_url (bool): If True, generate a pre-signed URL for the uploaded image. Defaults to False.
277
+ Raises:
278
+ Exception: If there is an error uploading the image.
243
279
 
244
280
  Keyword Args:
245
281
  format_file (str): Format of the image. Defaults to 'png'.
@@ -258,6 +294,13 @@ class S3Client:
258
294
  else:
259
295
  fig = kwargs.get("fig", None)
260
296
  object_name = kwargs.get("object_name", None)
297
+
298
+ overwrite = kwargs.get("overwrite", False)
299
+ presigned_url = kwargs.get("presigned_url", False)
300
+
301
+ # Get S3 client and resource
302
+ s3_client = self._get_s3_client()
303
+ s3_resource = self._get_s3_resource()
261
304
 
262
305
  if fig is None:
263
306
  raise Exception("Figure is None")
@@ -268,6 +311,12 @@ class S3Client:
268
311
  format_file : FormatFile = kwargs.get("format_file", "svg")
269
312
  mimetypes = "image/svg+xml"
270
313
 
314
+ if not overwrite and self.file_exists(object_name):
315
+ print(f"File {object_name} already exists in the bucket {self.bucket_name}. Use overwrite=True to overwrite it.")
316
+ if presigned_url:
317
+ return self._create_url(s3_client, self.bucket_name, object_name), False
318
+ return object_name, False
319
+
271
320
  if format_file not in ["png", "jpeg", "svg", "html"]:
272
321
  raise Exception("Invalid format_file provided. Supported formats are: png, jpeg, svg, html")
273
322
  if format_file == "png":
@@ -281,10 +330,6 @@ class S3Client:
281
330
  else:
282
331
  raise Exception("Invalid MIME type provided")
283
332
 
284
- # Get S3 client and resource
285
- s3_client = self._get_s3_client()
286
- s3_resource = self._get_s3_resource()
287
-
288
333
  if format_file == "html":
289
334
  # Convert the figure to SVG
290
335
  file_text = self._html_from_figure(fig)
@@ -297,13 +342,13 @@ class S3Client:
297
342
  s3_resource.Bucket(self.bucket_name).Object(object_name).put(Body=file_buffer, ContentType=mimetypes)
298
343
 
299
344
  # Generate and return a pre-signed URL for the uploaded image
300
- return self._create_url(s3_client, self.bucket_name, object_name)
345
+ return self._create_url(s3_client, self.bucket_name, object_name), True
301
346
 
302
347
  except Exception as e:
303
348
  logger.error(f"Error uploading image: {str(e)}")
304
349
  raise Exception(f"Error uploading image: {str(e)}")
305
350
 
306
- def upload_from_dataframe(self, *args : Any, **kwargs: Any) -> str:
351
+ def upload_from_dataframe(self, *args : Any, **kwargs: Any) -> tuple[str, bool]:
307
352
  """
308
353
  Upload a DataFrame as an Excel file to an S3 bucket and generate a pre-signed URL.
309
354
 
@@ -312,6 +357,10 @@ class S3Client:
312
357
  **kwargs (Any): Additional keyword arguments for AWS credentials, bucket name, and object name.
313
358
  Keyword Args:
314
359
  format_file (str): Format of the file. Defaults to 'xlsx'.
360
+ overwrite (bool): If True, overwrite the existing file in S3. Defaults to False.
361
+ presigned_url (bool): If True, generate a pre-signed URL for the uploaded file. Defaults to False.
362
+ Raises:
363
+ Exception: If there is an error uploading the file.
315
364
 
316
365
  Returns:
317
366
  str: Pre-signed URL for the uploaded file.
@@ -329,6 +378,9 @@ class S3Client:
329
378
  # Get the DataFrame and object name from the keyword arguments
330
379
  df = kwargs.get("df", None)
331
380
  object_name = kwargs.get("object_name", None)
381
+
382
+ overwrite = kwargs.get("overwrite", False)
383
+ presigned_url = kwargs.get("presigned_url", False)
332
384
 
333
385
  if df is None:
334
386
  raise Exception("Figure is None")
@@ -350,8 +402,15 @@ class S3Client:
350
402
  else:
351
403
  raise Exception("Invalid MIME type provided")
352
404
 
405
+ # Get S3 client and resource
353
406
  s3_client = self._get_s3_client()
354
407
  s3_resource = self._get_s3_resource()
408
+
409
+ if not overwrite and self.file_exists(object_name):
410
+ print(f"File {object_name} already exists in the bucket {self.bucket_name}. Use overwrite=True to overwrite it.")
411
+ if presigned_url:
412
+ return self._create_url(s3_client, self.bucket_name, object_name), False
413
+ return object_name, False
355
414
 
356
415
  # Create a file buffer
357
416
  ext: str = ""
@@ -382,7 +441,7 @@ class S3Client:
382
441
 
383
442
  logger.info(f"Uploaded file to S3: {object_name}")
384
443
 
385
- return self._create_url(s3_client, self.bucket_name, object_name)
444
+ return self._create_url(s3_client, self.bucket_name, object_name), True
386
445
  except Exception as e:
387
446
  logger.error(f"Error uploading file: {str(e)}")
388
447
  raise Exception(f"Error uploading file: {str(e)}")
@@ -413,15 +472,19 @@ class S3Client:
413
472
  logger.error(f"Error deleting files: {str(e)}")
414
473
  raise Exception(f"Error deleting files: {str(e)}")
415
474
 
416
- def upload_to_pdf(self, *args: Any, **kwargs: Any) -> str:
475
+ def upload_to_pdf(self, *args: Any, **kwargs: Any) -> tuple[str, bool]:
417
476
  """
418
477
  Export the given text as a PDF and upload it to the S3 bucket.
419
478
 
420
479
  Args:
421
480
  text (str): The text to write in the PDF.
422
481
  object_name (str): The name of the S3 object.
482
+ presigned_url (bool): If True, generate a pre-signed URL for the uploaded PDF. Defaults to False.
483
+ overwrite (bool): If True, overwrite the existing file in S3. Defaults to False
484
+
423
485
  Raises:
424
486
  Exception: If there is an error exporting the PDF.
487
+
425
488
  Returns:
426
489
  str: Pre-signed URL for the uploaded PDF.
427
490
  """
@@ -432,6 +495,9 @@ class S3Client:
432
495
  else:
433
496
  text = kwargs.get("text", None)
434
497
  object_name = kwargs.get("object_name", None)
498
+
499
+ overwrite = kwargs.get("overwrite", False)
500
+ presigned_url = kwargs.get("presigned_url", False)
435
501
 
436
502
  if text is None:
437
503
  raise Exception("Text is None")
@@ -440,8 +506,15 @@ class S3Client:
440
506
  raise Exception("Object name is None")
441
507
 
442
508
  mimetypes = "application/pdf"
509
+ # Get S3 client and resource
443
510
  s3_client = self._get_s3_client()
444
511
  s3_resource = self._get_s3_resource()
512
+
513
+ if not overwrite and self.file_exists(object_name):
514
+ print(f"File {object_name} already exists in the bucket {self.bucket_name}. Use overwrite=True to overwrite it.")
515
+ if presigned_url:
516
+ return self._create_url(s3_client, self.bucket_name, object_name), False
517
+ return object_name, False
445
518
 
446
519
  # Crea il PDF in memoria
447
520
  pdf_buffer = BytesIO()
@@ -450,29 +523,47 @@ class S3Client:
450
523
  c.setFont("Helvetica", 10)
451
524
  x_margin = 20 * mm
452
525
  y = height - 20 * mm
526
+ max_width = width - 2 * x_margin
527
+
528
+ def split_line(line, font_name, font_size):
529
+ # Divide la riga in più righe se supera la larghezza massima
530
+ words = line.split()
531
+ lines = []
532
+ current = ""
533
+ for word in words:
534
+ test = current + (" " if current else "") + word
535
+ if c.stringWidth(test, font_name, font_size) <= max_width:
536
+ current = test
537
+ else:
538
+ if current:
539
+ lines.append(current)
540
+ current = word
541
+ if current:
542
+ lines.append(current)
543
+ return lines
453
544
 
454
545
  for line in text.strip().split('\n'):
455
546
  line = line.strip()
456
- if y < 20 * mm:
457
- c.showPage()
458
- c.setFont("Helvetica", 10)
459
- y = height - 20 * mm
460
-
461
547
  # Markdown-style header detection
462
548
  if line.startswith("### "):
463
- c.setFont("Helvetica-Bold", 11)
549
+ font_name, font_size = "Helvetica-Bold", 11
464
550
  line = line[4:]
465
551
  elif line.startswith("## "):
466
- c.setFont("Helvetica-Bold", 12)
552
+ font_name, font_size = "Helvetica-Bold", 12
467
553
  line = line[3:]
468
554
  elif line.startswith("# "):
469
- c.setFont("Helvetica-Bold", 14)
555
+ font_name, font_size = "Helvetica-Bold", 14
470
556
  line = line[2:]
471
557
  else:
472
- c.setFont("Helvetica", 10)
558
+ font_name, font_size = "Helvetica", 10
473
559
 
474
- c.drawString(x_margin, y, line)
475
- y -= 12
560
+ for subline in split_line(line, font_name, font_size):
561
+ if y < 20 * mm + font_size:
562
+ c.showPage()
563
+ y = height - 20 * mm
564
+ c.setFont(font_name, font_size)
565
+ c.drawString(x_margin, y, subline)
566
+ y -= font_size + 2 # Spazio tra le righe
476
567
 
477
568
  c.save()
478
569
  pdf_buffer.seek(0)
@@ -482,7 +573,7 @@ class S3Client:
482
573
  Body=pdf_buffer,
483
574
  ContentType=mimetypes
484
575
  )
485
- return self._create_url(s3_client, self.bucket_name, object_name)
576
+ return self._create_url(s3_client, self.bucket_name, object_name), True
486
577
 
487
578
  except Exception as e:
488
579
  logger.error(f"Error exporting PDF: {str(e)}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyaws-s3
3
- Version: 1.0.23
3
+ Version: 1.0.27
4
4
  Summary: A Python package for AWS S3 utilities
5
5
  Author-email: Giuseppe Zileni <giuseppe.zileni@gmail.com>
6
6
  Keywords: aws,s3,utilities
@@ -0,0 +1,7 @@
1
+ pyaws_s3/__init__.py,sha256=Tr7xJiCKOMWYydOJ4kxHlA7AR1X3pRsJ8MjxJev2wsw,24
2
+ pyaws_s3/s3.py,sha256=x_7M_3qTPyoExn6-Hw790YI4DQLFbIyBInXTYjDY3jQ,27780
3
+ pyaws_s3-1.0.27.dist-info/licenses/LICENSE.md,sha256=7WXohDebeZpcVn_nH2aIaLhFZRvZBdcPSqWsO12lhwM,1074
4
+ pyaws_s3-1.0.27.dist-info/METADATA,sha256=aHF-ijVr5cQGXQYOBIMeBT9MEjNmZx-pJ9zPIO_D5kc,5464
5
+ pyaws_s3-1.0.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
+ pyaws_s3-1.0.27.dist-info/top_level.txt,sha256=MxSSC4Q8Vr32wKgrUAlwT4BTXwqUaG_CAWoBuPeXYjQ,9
7
+ pyaws_s3-1.0.27.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- pyaws_s3/__init__.py,sha256=Tr7xJiCKOMWYydOJ4kxHlA7AR1X3pRsJ8MjxJev2wsw,24
2
- pyaws_s3/s3.py,sha256=EfbJUo2SwRszaJE-9I89yx5-5HoTgr8cI3-M6A6WUXE,22647
3
- pyaws_s3-1.0.23.dist-info/licenses/LICENSE.md,sha256=7WXohDebeZpcVn_nH2aIaLhFZRvZBdcPSqWsO12lhwM,1074
4
- pyaws_s3-1.0.23.dist-info/METADATA,sha256=0t90l4Zpe8B3NOCXyidsmBH_yQFJAIvFcCMWqcmsYV0,5464
5
- pyaws_s3-1.0.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
- pyaws_s3-1.0.23.dist-info/top_level.txt,sha256=MxSSC4Q8Vr32wKgrUAlwT4BTXwqUaG_CAWoBuPeXYjQ,9
7
- pyaws_s3-1.0.23.dist-info/RECORD,,