cloudtoolbox 0.4.0__tar.gz → 0.6.0__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.
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/PKG-INFO +3 -2
- cloudtoolbox-0.6.0/cloud/amazon/helpers.py +22 -0
- cloudtoolbox-0.6.0/cloud/amazon/sns.py +32 -0
- cloudtoolbox-0.6.0/cloud/amazon/sqs.py +32 -0
- cloudtoolbox-0.6.0/cloud/google/pubsub.py +49 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/protocols.py +10 -2
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloudtoolbox.egg-info/PKG-INFO +3 -2
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloudtoolbox.egg-info/SOURCES.txt +1 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/pyproject.toml +1 -1
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/tests/test_factory.py +21 -0
- cloudtoolbox-0.4.0/cloud/amazon/sns.py +0 -12
- cloudtoolbox-0.4.0/cloud/amazon/sqs.py +0 -12
- cloudtoolbox-0.4.0/cloud/google/pubsub.py +0 -12
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/LICENSE +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/README.md +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/__init__.py +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/amazon/__init__.py +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/amazon/s3.py +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/factory.py +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/google/__init__.py +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloud/google/storage.py +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloudtoolbox.egg-info/dependency_links.txt +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloudtoolbox.egg-info/requires.txt +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/cloudtoolbox.egg-info/top_level.txt +0 -0
- {cloudtoolbox-0.4.0 → cloudtoolbox-0.6.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudtoolbox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Toolbox for the cloud.
|
|
5
5
|
Author-email: Dotz Developers <devs-dotz@dotz.com>
|
|
6
6
|
Project-URL: Repository, https://github.com/DotzInc/cloud-toolbox
|
|
@@ -28,6 +28,7 @@ Provides-Extra: all
|
|
|
28
28
|
Requires-Dist: boto3; extra == "all"
|
|
29
29
|
Requires-Dist: google-cloud-pubsub; extra == "all"
|
|
30
30
|
Requires-Dist: google-cloud-storage; extra == "all"
|
|
31
|
+
Dynamic: license-file
|
|
31
32
|
|
|
32
33
|
# Cloud Toolbox
|
|
33
34
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Mapping, Union
|
|
2
|
+
|
|
3
|
+
DataType = Union[str, bytes, int, float]
|
|
4
|
+
MessageAttributes = Mapping[str, Mapping[str, DataType]]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def build_attributes(data: Mapping[str, DataType]) -> MessageAttributes:
|
|
8
|
+
attrs = {}
|
|
9
|
+
|
|
10
|
+
for key, value in data.items():
|
|
11
|
+
if isinstance(value, str):
|
|
12
|
+
attr = {"StringValue": value, "DataType": "String"}
|
|
13
|
+
elif isinstance(value, bytes):
|
|
14
|
+
attr = {"BinaryValue": value, "DataType": "Binary"}
|
|
15
|
+
elif isinstance(value, (int, float)):
|
|
16
|
+
attr = {"StringValue": str(value), "DataType": "Number"}
|
|
17
|
+
else:
|
|
18
|
+
raise TypeError(f"{value} of type {type(value).__name__} is not supported")
|
|
19
|
+
|
|
20
|
+
attrs[key] = attr
|
|
21
|
+
|
|
22
|
+
return attrs
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from typing import Any, Mapping, Optional
|
|
3
|
+
|
|
4
|
+
import boto3
|
|
5
|
+
|
|
6
|
+
from cloud.amazon import helpers
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Publisher:
|
|
10
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
|
11
|
+
self.client = boto3.client("sns", *args, **kwargs)
|
|
12
|
+
|
|
13
|
+
def publish(
|
|
14
|
+
self,
|
|
15
|
+
recipient: str,
|
|
16
|
+
message: str,
|
|
17
|
+
/,
|
|
18
|
+
*,
|
|
19
|
+
group: str = "",
|
|
20
|
+
attrs: Optional[Mapping[str, Any]] = None,
|
|
21
|
+
) -> str:
|
|
22
|
+
kwargs = {}
|
|
23
|
+
|
|
24
|
+
if group:
|
|
25
|
+
kwargs["MessageGroupId"] = group
|
|
26
|
+
kwargs["MessageDeduplicationId"] = str(uuid.uuid4())
|
|
27
|
+
|
|
28
|
+
if attrs:
|
|
29
|
+
kwargs["MessageAttributes"] = helpers.build_attributes(attrs)
|
|
30
|
+
|
|
31
|
+
response = self.client.publish(TargetArn=recipient, Message=message, **kwargs)
|
|
32
|
+
return response["MessageId"]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from typing import Any, Mapping, Optional
|
|
3
|
+
|
|
4
|
+
import boto3
|
|
5
|
+
|
|
6
|
+
from cloud.amazon import helpers
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Publisher:
|
|
10
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
|
11
|
+
self.client = boto3.client("sqs", *args, **kwargs)
|
|
12
|
+
|
|
13
|
+
def publish(
|
|
14
|
+
self,
|
|
15
|
+
recipient: str,
|
|
16
|
+
message: str,
|
|
17
|
+
/,
|
|
18
|
+
*,
|
|
19
|
+
group: str = "",
|
|
20
|
+
attrs: Optional[Mapping[str, Any]] = None,
|
|
21
|
+
) -> str:
|
|
22
|
+
kwargs = {}
|
|
23
|
+
|
|
24
|
+
if group:
|
|
25
|
+
kwargs["MessageGroupId"] = group
|
|
26
|
+
kwargs["MessageDeduplicationId"] = str(uuid.uuid4())
|
|
27
|
+
|
|
28
|
+
if attrs:
|
|
29
|
+
kwargs["MessageAttributes"] = helpers.build_attributes(attrs)
|
|
30
|
+
|
|
31
|
+
response = self.client.send_message(QueueUrl=recipient, MessageBody=message, **kwargs)
|
|
32
|
+
return response["MessageId"]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from threading import Lock
|
|
3
|
+
from typing import Any, Dict, Hashable, Mapping, Optional
|
|
4
|
+
|
|
5
|
+
from google.cloud import pubsub_v1
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Publisher:
|
|
9
|
+
_clients: Dict[Hashable, pubsub_v1.PublisherClient] = {}
|
|
10
|
+
_lock = Lock()
|
|
11
|
+
|
|
12
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
13
|
+
self.client = self._shared_client(*args, **kwargs)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def _shared_client(cls, *args: Any, **kwargs: Any) -> pubsub_v1.PublisherClient:
|
|
17
|
+
try:
|
|
18
|
+
key = (os.getpid(), args, frozenset(kwargs.items()))
|
|
19
|
+
hash(key)
|
|
20
|
+
except TypeError:
|
|
21
|
+
return pubsub_v1.PublisherClient(*args, **kwargs)
|
|
22
|
+
|
|
23
|
+
client = cls._clients.get(key)
|
|
24
|
+
if client is None:
|
|
25
|
+
with cls._lock:
|
|
26
|
+
client = cls._clients.get(key)
|
|
27
|
+
if client is None:
|
|
28
|
+
client = pubsub_v1.PublisherClient(*args, **kwargs)
|
|
29
|
+
cls._clients[key] = client
|
|
30
|
+
return client
|
|
31
|
+
|
|
32
|
+
def publish(
|
|
33
|
+
self,
|
|
34
|
+
recipient: str,
|
|
35
|
+
message: str,
|
|
36
|
+
/,
|
|
37
|
+
*,
|
|
38
|
+
group: str = "",
|
|
39
|
+
attrs: Optional[Mapping[str, Any]] = None,
|
|
40
|
+
) -> str:
|
|
41
|
+
kwargs = attrs or {}
|
|
42
|
+
future = self.client.publish(recipient, data=message.encode(), ordering_key=group, **kwargs)
|
|
43
|
+
return future.result()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OrderedPublisher(Publisher):
|
|
47
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
48
|
+
opts = pubsub_v1.types.PublisherOptions(enable_message_ordering=True)
|
|
49
|
+
super().__init__(*args, publisher_options=opts, **kwargs)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Protocol, runtime_checkable
|
|
1
|
+
from typing import Any, Mapping, Optional, Protocol, runtime_checkable
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
@runtime_checkable
|
|
@@ -25,4 +25,12 @@ class StorageURLSigner(Protocol):
|
|
|
25
25
|
|
|
26
26
|
@runtime_checkable
|
|
27
27
|
class MessagePublisher(Protocol):
|
|
28
|
-
def publish(
|
|
28
|
+
def publish(
|
|
29
|
+
self,
|
|
30
|
+
recipient: str,
|
|
31
|
+
message: str,
|
|
32
|
+
/,
|
|
33
|
+
*,
|
|
34
|
+
group: str = "",
|
|
35
|
+
attrs: Optional[Mapping[str, Any]] = None,
|
|
36
|
+
) -> str: ...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudtoolbox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Toolbox for the cloud.
|
|
5
5
|
Author-email: Dotz Developers <devs-dotz@dotz.com>
|
|
6
6
|
Project-URL: Repository, https://github.com/DotzInc/cloud-toolbox
|
|
@@ -28,6 +28,7 @@ Provides-Extra: all
|
|
|
28
28
|
Requires-Dist: boto3; extra == "all"
|
|
29
29
|
Requires-Dist: google-cloud-pubsub; extra == "all"
|
|
30
30
|
Requires-Dist: google-cloud-storage; extra == "all"
|
|
31
|
+
Dynamic: license-file
|
|
31
32
|
|
|
32
33
|
# Cloud Toolbox
|
|
33
34
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cloudtoolbox"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "Toolbox for the cloud."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
authors = [{ name = "Dotz Developers", email = "devs-dotz@dotz.com" }]
|
|
@@ -101,6 +101,19 @@ class TestStorageURLSigner(unittest.TestCase):
|
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
class TestMessagePublisherFactory(unittest.TestCase):
|
|
104
|
+
def setUp(self):
|
|
105
|
+
pubsub.Publisher._clients.clear()
|
|
106
|
+
|
|
107
|
+
def tearDown(self):
|
|
108
|
+
pubsub.Publisher._clients.clear()
|
|
109
|
+
|
|
110
|
+
@mock.patch("google.cloud.pubsub_v1.PublisherClient")
|
|
111
|
+
def test_google_publisher_shares_client(self, client):
|
|
112
|
+
Publisher = factory.message_publisher(pubsub.Publisher)
|
|
113
|
+
|
|
114
|
+
self.assertIs(Publisher().client, Publisher().client)
|
|
115
|
+
client.assert_called_once_with()
|
|
116
|
+
|
|
104
117
|
@mock.patch("google.cloud.pubsub_v1.PublisherClient")
|
|
105
118
|
def test_google_publisher(self, _):
|
|
106
119
|
Publisher = factory.message_publisher(pubsub.Publisher)
|
|
@@ -109,6 +122,14 @@ class TestMessagePublisherFactory(unittest.TestCase):
|
|
|
109
122
|
self.assertIsInstance(publisher, MessagePublisher)
|
|
110
123
|
self.assertIsInstance(publisher, pubsub.Publisher)
|
|
111
124
|
|
|
125
|
+
@mock.patch("google.cloud.pubsub_v1.PublisherClient")
|
|
126
|
+
def test_google_ordered_publisher(self, _):
|
|
127
|
+
OrderedPublisher = factory.message_publisher(pubsub.OrderedPublisher)
|
|
128
|
+
publisher = OrderedPublisher()
|
|
129
|
+
|
|
130
|
+
self.assertIsInstance(publisher, MessagePublisher)
|
|
131
|
+
self.assertIsInstance(publisher, pubsub.OrderedPublisher)
|
|
132
|
+
|
|
112
133
|
@mock.patch("boto3.client")
|
|
113
134
|
def test_amazon_publisher(self, _):
|
|
114
135
|
for cls in (sns.Publisher, sqs.Publisher):
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
import boto3
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Publisher:
|
|
7
|
-
def __init__(self, *args: Any, **kwargs: Any):
|
|
8
|
-
self.client = boto3.client("sns", *args, **kwargs)
|
|
9
|
-
|
|
10
|
-
def publish(self, recipient: str, message: str, **attrs: Any) -> str:
|
|
11
|
-
response = self.client.publish(TargetArn=recipient, Message=message, **attrs)
|
|
12
|
-
return response["MessageId"]
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
import boto3
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Publisher:
|
|
7
|
-
def __init__(self, *args: Any, **kwargs: Any):
|
|
8
|
-
self.client = boto3.client("sqs", *args, **kwargs)
|
|
9
|
-
|
|
10
|
-
def publish(self, recipient: str, message: str, **attrs: Any) -> str:
|
|
11
|
-
response = self.client.send_message(QueueUrl=recipient, MessageBody=message, **attrs)
|
|
12
|
-
return response["MessageId"]
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from google.cloud import pubsub_v1
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Publisher:
|
|
7
|
-
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
8
|
-
self.client = pubsub_v1.PublisherClient(*args, **kwargs)
|
|
9
|
-
|
|
10
|
-
def publish(self, recipient: str, message: str, **attrs: Any) -> str:
|
|
11
|
-
future = self.client.publish(recipient, data=message.encode(), **attrs)
|
|
12
|
-
return future.result()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|