reach_commons 0.17.1__tar.gz → 0.17.3__tar.gz

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.
Files changed (33) hide show
  1. {reach_commons-0.17.1 → reach_commons-0.17.3}/PKG-INFO +1 -1
  2. {reach_commons-0.17.1 → reach_commons-0.17.3}/pyproject.toml +1 -1
  3. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/app_logging/log_deprecated_endpoints.py +1 -1
  4. reach_commons-0.17.3/reach_commons/reach_aws/s3.py +113 -0
  5. reach_commons-0.17.1/reach_commons/reach_aws/s3.py +0 -63
  6. {reach_commons-0.17.1 → reach_commons-0.17.3}/README.md +0 -0
  7. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/__init__.py +0 -0
  8. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/app_logging/__init__.py +0 -0
  9. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/app_logging/http_logger.py +0 -0
  10. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/app_logging/logger.py +0 -0
  11. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/app_logging/logging_config.py +0 -0
  12. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/clients/__init__.py +0 -0
  13. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/clients/event_processor.py +0 -0
  14. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/clients/hubspot.py +0 -0
  15. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/clients/outscraper.py +0 -0
  16. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/clients/reach_data_bridge.py +0 -0
  17. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/clients/reach_ops_api.py +0 -0
  18. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/mongo/__init__.py +0 -0
  19. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/mongo/customer_persistence.py +0 -0
  20. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/mongo/customer_persistence_async.py +0 -0
  21. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/mongo/validation/__init__.py +0 -0
  22. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/__init__.py +0 -0
  23. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/commons.py +0 -0
  24. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/dynamo_db.py +0 -0
  25. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/exceptions.py +0 -0
  26. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/firehose.py +0 -0
  27. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/kms.py +0 -0
  28. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_aws/sqs.py +0 -0
  29. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/reach_base_model.py +0 -0
  30. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/redis_manager.py +0 -0
  31. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/sms_smart_encoding.py +0 -0
  32. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/utils.py +0 -0
  33. {reach_commons-0.17.1 → reach_commons-0.17.3}/reach_commons/validations.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reach_commons
3
- Version: 0.17.1
3
+ Version: 0.17.3
4
4
  Summary: Reach Commons is a versatile utility library designed to streamline and enhance development workflows within the Reach ecosystem.
5
5
  License: MIT
6
6
  Author: Wilson Moraes
@@ -1,7 +1,7 @@
1
1
  # isort .; black .; poetry build; poetry publish
2
2
  [tool.poetry]
3
3
  name = "reach_commons"
4
- version = "0.17.1"
4
+ version = "0.17.3"
5
5
  description = "Reach Commons is a versatile utility library designed to streamline and enhance development workflows within the Reach ecosystem."
6
6
  authors = ["Wilson Moraes <wmoraes@getreach.ai>"]
7
7
  license = "MIT"
@@ -46,7 +46,7 @@ def add_deprecation_headers(
46
46
  )
47
47
 
48
48
  elif current_date >= removal_date:
49
- logger.error(
49
+ logger.warning(
50
50
  f"Access to removed endpoint: {method} {path}. "
51
51
  f"Removal date was {removal_date_str}."
52
52
  + (f" Replacement endpoint: {replacement_url}" if replacement_url else "")
@@ -0,0 +1,113 @@
1
+ from functools import cached_property
2
+ from io import BytesIO
3
+ from urllib.parse import unquote, urlparse
4
+
5
+ import boto3
6
+
7
+ from reach_commons.app_logging.logger import get_reach_logger
8
+
9
+
10
+ class S3Client:
11
+ def __init__(
12
+ self,
13
+ logger=get_reach_logger(),
14
+ region_name="us-east-1",
15
+ profile_name=None,
16
+ ):
17
+ self.logger = logger
18
+ self.region_name = region_name
19
+ self.profile_name = profile_name
20
+
21
+ @cached_property
22
+ def client(self):
23
+ session = boto3.Session(
24
+ region_name=self.region_name, profile_name=self.profile_name
25
+ )
26
+
27
+ return session.client("s3")
28
+
29
+ def _parse_s3_url(self, url: str) -> tuple[str, str]:
30
+ """
31
+ Support various S3 URL formats:
32
+ - s3://bucket/key
33
+ - https://bucket.s3.amazonaws.com/key
34
+ - https://bucket.s3.<region>.amazonaws.com/key
35
+ - https://s3.<region>.amazonaws.com/bucket/key (path-style)
36
+ - https://s3.amazonaws.com/bucket/key (path-style)
37
+ """
38
+ p = urlparse(url)
39
+
40
+ if p.scheme == "s3":
41
+ bucket = p.netloc
42
+ key = p.path.lstrip("/")
43
+ return bucket, unquote(key)
44
+
45
+ host = p.netloc
46
+ path = p.path.lstrip("/")
47
+
48
+ # Path-style: s3.<region>.amazonaws.com/bucket/key ou s3.amazonaws.com/bucket/key
49
+ if host.startswith("s3.") or host == "s3.amazonaws.com":
50
+ parts = path.split("/", 1)
51
+ if not parts or not parts[0]:
52
+ raise ValueError(f"Invalid S3 URL (missing bucket in path): {url}")
53
+ bucket = parts[0]
54
+ key = parts[1] if len(parts) > 1 else ""
55
+ return bucket, unquote(key)
56
+
57
+ # Virtual-hosted: bucket.s3[.<region>].amazonaws.com/key
58
+ bucket = host.split(".")[0]
59
+ key = path
60
+ if not bucket:
61
+ raise ValueError(f"Invalid S3 URL (missing bucket in host): {url}")
62
+ return bucket, unquote(key)
63
+
64
+ def get_object(self, s3_bucket_name, s3_key):
65
+ try:
66
+ s3_object = self.client.get_object(Bucket=s3_bucket_name, Key=s3_key)
67
+ actual_message_body = s3_object["Body"].read().decode("utf-8")
68
+
69
+ self.logger.info(
70
+ f"Retrieved object from S3: {s3_key} in bucket: {s3_bucket_name}"
71
+ )
72
+ return actual_message_body
73
+ except Exception as e:
74
+ self.logger.error(
75
+ f"Error retrieving object {s3_key} from bucket: {s3_bucket_name}: {str(e)}"
76
+ )
77
+
78
+ return None
79
+
80
+ def add_object(self, s3_bucket_name, s3_key, str_content):
81
+ try:
82
+ file_object = BytesIO(str_content.encode("utf-8"))
83
+
84
+ self.client.upload_fileobj(
85
+ Fileobj=file_object, Bucket=s3_bucket_name, Key=s3_key
86
+ )
87
+ url = (
88
+ f"https://{s3_bucket_name}.s3.{self.region_name}.amazonaws.com/{s3_key}"
89
+ )
90
+
91
+ self.logger.info(
92
+ f"Uploaded object to S3: {s3_key} in bucket: {s3_bucket_name}"
93
+ )
94
+ return url
95
+ except Exception as e:
96
+ self.logger.error(
97
+ f"Error uploading object {s3_key} to bucket: {s3_bucket_name}: {str(e)}"
98
+ )
99
+ return None
100
+
101
+ def delete_object_by_url(self, url: str) -> bool:
102
+ """
103
+ Deleta um objeto no S3 recebendo apenas a URL direta.
104
+ Retorna True se deletou (ou o objeto não existia) e False se falhou.
105
+ """
106
+ try:
107
+ bucket, key = self._parse_s3_url(url)
108
+ self.client.delete_object(Bucket=bucket, Key=key)
109
+ self.logger.info(f"Deleted object from S3: {key} in bucket: {bucket}")
110
+ return True
111
+ except Exception as e:
112
+ self.logger.error(f"Error deleting S3 object from url '{url}': {e}")
113
+ return False
@@ -1,63 +0,0 @@
1
- from functools import cached_property
2
- from io import BytesIO
3
-
4
- import boto3
5
-
6
- from reach_commons.app_logging.logger import get_reach_logger
7
-
8
-
9
- class S3Client:
10
- def __init__(
11
- self,
12
- logger=get_reach_logger(),
13
- region_name="us-east-1",
14
- profile_name=None,
15
- ):
16
- self.logger = logger
17
- self.region_name = region_name
18
- self.profile_name = profile_name
19
-
20
- @cached_property
21
- def client(self):
22
- session = boto3.Session(
23
- region_name=self.region_name, profile_name=self.profile_name
24
- )
25
-
26
- return session.client("s3")
27
-
28
- def get_object(self, s3_bucket_name, s3_key):
29
- try:
30
- s3_object = self.client.get_object(Bucket=s3_bucket_name, Key=s3_key)
31
- actual_message_body = s3_object["Body"].read().decode("utf-8")
32
-
33
- self.logger.info(
34
- f"Retrieved object from S3: {s3_key} from bucket: {s3_bucket_name}"
35
- )
36
- return actual_message_body
37
- except Exception as e:
38
- self.logger.error(
39
- f"Error retrieving object {s3_key} from bucket: {s3_bucket_name}: {str(e)}"
40
- )
41
-
42
- return None
43
-
44
- def add_object(self, s3_bucket_name, s3_key, str_content):
45
- try:
46
- file_object = BytesIO(str_content.encode("utf-8"))
47
-
48
- self.client.upload_fileobj(
49
- Fileobj=file_object, Bucket=s3_bucket_name, Key=s3_key
50
- )
51
- url = (
52
- f"https://{s3_bucket_name}.s3.{self.region_name}.amazonaws.com/{s3_key}"
53
- )
54
-
55
- self.logger.info(
56
- f"Uploaded object to S3: {s3_key} in bucket: {s3_bucket_name}"
57
- )
58
- return url
59
- except Exception as e:
60
- self.logger.error(
61
- f"Error uploading object {s3_key} to bucket: {s3_bucket_name}: {str(e)}"
62
- )
63
- return None
File without changes