cloudtoolbox 0.1.0__tar.gz → 0.3.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.1.0 → cloudtoolbox-0.3.0}/LICENSE +1 -1
- cloudtoolbox-0.3.0/PKG-INFO +86 -0
- cloudtoolbox-0.3.0/README.md +55 -0
- cloudtoolbox-0.3.0/cloud/amazon/s3.py +40 -0
- cloudtoolbox-0.3.0/cloud/amazon/sns.py +11 -0
- cloudtoolbox-0.3.0/cloud/amazon/sqs.py +11 -0
- cloudtoolbox-0.3.0/cloud/factory.py +53 -0
- cloudtoolbox-0.3.0/cloud/google/storage.py +42 -0
- cloudtoolbox-0.3.0/cloud/protocols.py +28 -0
- cloudtoolbox-0.3.0/cloudtoolbox.egg-info/PKG-INFO +86 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloudtoolbox.egg-info/SOURCES.txt +2 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloudtoolbox.egg-info/requires.txt +5 -0
- cloudtoolbox-0.3.0/pyproject.toml +53 -0
- cloudtoolbox-0.3.0/tests/test_factory.py +126 -0
- cloudtoolbox-0.1.0/PKG-INFO +0 -19
- cloudtoolbox-0.1.0/README.md +0 -3
- cloudtoolbox-0.1.0/cloud/amazon/s3.py +0 -11
- cloudtoolbox-0.1.0/cloud/factory.py +0 -29
- cloudtoolbox-0.1.0/cloud/google/storage.py +0 -13
- cloudtoolbox-0.1.0/cloud/protocols.py +0 -11
- cloudtoolbox-0.1.0/cloudtoolbox.egg-info/PKG-INFO +0 -19
- cloudtoolbox-0.1.0/pyproject.toml +0 -45
- cloudtoolbox-0.1.0/tests/test_factory.py +0 -57
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloud/__init__.py +0 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloud/amazon/__init__.py +0 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloud/google/__init__.py +0 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloud/google/pubsub.py +0 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloudtoolbox.egg-info/dependency_links.txt +0 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/cloudtoolbox.egg-info/top_level.txt +0 -0
- {cloudtoolbox-0.1.0 → cloudtoolbox-0.3.0}/setup.cfg +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cloudtoolbox
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Toolbox for the cloud.
|
|
5
|
+
Author-email: Dotz Developers <devs-dotz@dotz.com>
|
|
6
|
+
Project-URL: Repository, https://github.com/DotzInc/cloud-toolbox
|
|
7
|
+
Keywords: cloud,tools,utilities,google,gcp,amazon,aws
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Internet
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: amazon
|
|
23
|
+
Requires-Dist: boto3; extra == "amazon"
|
|
24
|
+
Provides-Extra: google
|
|
25
|
+
Requires-Dist: google-cloud-pubsub; extra == "google"
|
|
26
|
+
Requires-Dist: google-cloud-storage; extra == "google"
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: boto3; extra == "all"
|
|
29
|
+
Requires-Dist: google-cloud-pubsub; extra == "all"
|
|
30
|
+
Requires-Dist: google-cloud-storage; extra == "all"
|
|
31
|
+
|
|
32
|
+
# Cloud Toolbox
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
Decouple your applications from cloud providers with carefully crafted service interfaces.
|
|
39
|
+
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
* Python 3.8+
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
To install Cloud Toolbox, use pip:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
pip install cloudtoolbox
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Extras
|
|
53
|
+
|
|
54
|
+
Cloud Toolbox offers the following optional dependencies for easy installation of provider SDKs:
|
|
55
|
+
|
|
56
|
+
* `cloudtoolbox[amazon]` - Installs the Amazon AWS SDK.
|
|
57
|
+
* `cloudtoolbox[google]` - Installs the Google Cloud SDK.
|
|
58
|
+
* `cloudtoolbox[all]` - Installs SDKs for both providers.
|
|
59
|
+
|
|
60
|
+
## Example
|
|
61
|
+
|
|
62
|
+
Uploading a file to Google Cloud Storage.
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from cloud import factory
|
|
66
|
+
from cloud.google.storage import Uploader
|
|
67
|
+
|
|
68
|
+
FileUploader = factory.storage_uploader(Uploader)
|
|
69
|
+
|
|
70
|
+
bucket = "my-bucket"
|
|
71
|
+
filename = "notes.txt"
|
|
72
|
+
filepath = f"/path/to/{filename}"
|
|
73
|
+
|
|
74
|
+
uploader = FileUploader()
|
|
75
|
+
uploader.upload(bucket, filename, filepath)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Switching from Cloud Storage to Amazon S3.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# Replace this import
|
|
82
|
+
from cloud.google.storage import Uploader
|
|
83
|
+
|
|
84
|
+
# For this one
|
|
85
|
+
from cloud.amazon.s3 import Uploader
|
|
86
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Cloud Toolbox
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Decouple your applications from cloud providers with carefully crafted service interfaces.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
* Python 3.8+
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
To install Cloud Toolbox, use pip:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
pip install cloudtoolbox
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Extras
|
|
22
|
+
|
|
23
|
+
Cloud Toolbox offers the following optional dependencies for easy installation of provider SDKs:
|
|
24
|
+
|
|
25
|
+
* `cloudtoolbox[amazon]` - Installs the Amazon AWS SDK.
|
|
26
|
+
* `cloudtoolbox[google]` - Installs the Google Cloud SDK.
|
|
27
|
+
* `cloudtoolbox[all]` - Installs SDKs for both providers.
|
|
28
|
+
|
|
29
|
+
## Example
|
|
30
|
+
|
|
31
|
+
Uploading a file to Google Cloud Storage.
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from cloud import factory
|
|
35
|
+
from cloud.google.storage import Uploader
|
|
36
|
+
|
|
37
|
+
FileUploader = factory.storage_uploader(Uploader)
|
|
38
|
+
|
|
39
|
+
bucket = "my-bucket"
|
|
40
|
+
filename = "notes.txt"
|
|
41
|
+
filepath = f"/path/to/{filename}"
|
|
42
|
+
|
|
43
|
+
uploader = FileUploader()
|
|
44
|
+
uploader.upload(bucket, filename, filepath)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Switching from Cloud Storage to Amazon S3.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
# Replace this import
|
|
51
|
+
from cloud.google.storage import Uploader
|
|
52
|
+
|
|
53
|
+
# For this one
|
|
54
|
+
from cloud.amazon.s3 import Uploader
|
|
55
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import boto3
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Client:
|
|
7
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
8
|
+
self.client = boto3.client("s3", *args, **kwargs)
|
|
9
|
+
|
|
10
|
+
def upload(self, bucket_name: str, destination_filename: str, source_filename: str) -> None:
|
|
11
|
+
self.client.upload_file(source_filename, bucket_name, destination_filename)
|
|
12
|
+
|
|
13
|
+
def download(self, bucket_name: str, source_filename: str, destination_filename: str) -> None:
|
|
14
|
+
self.client.download_file(bucket_name, source_filename, destination_filename)
|
|
15
|
+
|
|
16
|
+
def generate_presigned_url(
|
|
17
|
+
self,
|
|
18
|
+
bucket_name: str,
|
|
19
|
+
source_filename: str,
|
|
20
|
+
expiration: int,
|
|
21
|
+
) -> str:
|
|
22
|
+
url = self.client.generate_presigned_url(
|
|
23
|
+
ClientMethod="get_object",
|
|
24
|
+
Params={"Bucket": bucket_name, "Key": source_filename},
|
|
25
|
+
ExpiresIn=expiration,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
return url
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Uploader(Client):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Downloader(Client):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class URLSigner(Client):
|
|
40
|
+
pass
|
|
@@ -0,0 +1,11 @@
|
|
|
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) -> None:
|
|
11
|
+
self.client.publish(TargetArn=recipient, Message=message, **attrs)
|
|
@@ -0,0 +1,11 @@
|
|
|
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) -> None:
|
|
11
|
+
self.client.send_message(QueueUrl=recipient, MessageBody=message, **attrs)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Any, Callable, Type
|
|
2
|
+
|
|
3
|
+
from cloud.protocols import MessagePublisher, StorageDownloader, StorageUploader, StorageURLSigner
|
|
4
|
+
|
|
5
|
+
error_message = "%(class)s does not implement %(protocol)s protocol"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def storage_uploader(
|
|
9
|
+
uploader_class: Type[StorageUploader], *args: Any, **kwargs: Any
|
|
10
|
+
) -> Callable[[], StorageUploader]:
|
|
11
|
+
error = error_message % {"class": uploader_class.__name__, "protocol": "StorageUploader"}
|
|
12
|
+
assert issubclass(uploader_class, StorageUploader), error
|
|
13
|
+
|
|
14
|
+
def maker() -> StorageUploader:
|
|
15
|
+
return uploader_class(*args, **kwargs)
|
|
16
|
+
|
|
17
|
+
return maker
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def storage_downloader(
|
|
21
|
+
downloader_class: Type[StorageDownloader], *args: Any, **kwargs: Any
|
|
22
|
+
) -> Callable[[], StorageDownloader]:
|
|
23
|
+
error = error_message % {"class": downloader_class.__name__, "protocol": "StorageDownloader"}
|
|
24
|
+
assert issubclass(downloader_class, StorageDownloader), error
|
|
25
|
+
|
|
26
|
+
def maker() -> StorageDownloader:
|
|
27
|
+
return downloader_class(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
return maker
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def storage_urlsigner(
|
|
33
|
+
urlsigner_class: Type[StorageURLSigner], *args: Any, **kwargs: Any
|
|
34
|
+
) -> Callable[[], StorageURLSigner]:
|
|
35
|
+
error = error_message % {"class": urlsigner_class.__name__, "protocol": "StorageURLSigner"}
|
|
36
|
+
assert issubclass(urlsigner_class, StorageURLSigner), error
|
|
37
|
+
|
|
38
|
+
def maker() -> StorageURLSigner:
|
|
39
|
+
return urlsigner_class(*args, **kwargs)
|
|
40
|
+
|
|
41
|
+
return maker
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def message_publisher(
|
|
45
|
+
publisher_class: Type[MessagePublisher], *args: Any, **kwargs: Any
|
|
46
|
+
) -> Callable[[], MessagePublisher]:
|
|
47
|
+
error = error_message % {"class": publisher_class.__name__, "protocol": "MessagePublisher"}
|
|
48
|
+
assert issubclass(publisher_class, MessagePublisher), error
|
|
49
|
+
|
|
50
|
+
def maker() -> MessagePublisher:
|
|
51
|
+
return publisher_class(*args, **kwargs)
|
|
52
|
+
|
|
53
|
+
return maker
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from google.cloud import storage
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Client:
|
|
8
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
9
|
+
self.client = storage.Client(*args, **kwargs)
|
|
10
|
+
|
|
11
|
+
def upload(self, bucket_name: str, destination_filename: str, source_filename: str) -> None:
|
|
12
|
+
blob = self.client.bucket(bucket_name).blob(destination_filename)
|
|
13
|
+
blob.upload_from_filename(source_filename)
|
|
14
|
+
|
|
15
|
+
def download(self, bucket_name: str, source_filename: str, destination_filename: str) -> None:
|
|
16
|
+
blob = self.client.bucket(bucket_name).blob(source_filename)
|
|
17
|
+
blob.download_to_filename(destination_filename)
|
|
18
|
+
|
|
19
|
+
def generate_presigned_url(
|
|
20
|
+
self,
|
|
21
|
+
bucket_name: str,
|
|
22
|
+
source_filename: str,
|
|
23
|
+
expiration: int,
|
|
24
|
+
) -> str:
|
|
25
|
+
blob = self.client.bucket(bucket_name).blob(source_filename)
|
|
26
|
+
url = blob.generate_signed_url(
|
|
27
|
+
expiration=datetime.timedelta(seconds=expiration),
|
|
28
|
+
version="v4",
|
|
29
|
+
)
|
|
30
|
+
return url
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Uploader(Client):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Downloader(Client):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class URLSigner(Client):
|
|
42
|
+
pass
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any, Protocol, runtime_checkable
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@runtime_checkable
|
|
5
|
+
class StorageUploader(Protocol):
|
|
6
|
+
def upload(self, bucket_name: str, destination_filename: str, source_filename: str) -> None: ...
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class StorageDownloader(Protocol):
|
|
11
|
+
def download(
|
|
12
|
+
self, bucket_name: str, source_filename: str, destination_filename: str
|
|
13
|
+
) -> None: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class StorageURLSigner(Protocol):
|
|
18
|
+
def generate_presigned_url(
|
|
19
|
+
self,
|
|
20
|
+
bucket_name: str,
|
|
21
|
+
source_filename: str,
|
|
22
|
+
expiration: int,
|
|
23
|
+
) -> str: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@runtime_checkable
|
|
27
|
+
class MessagePublisher(Protocol):
|
|
28
|
+
def publish(self, recipient: str, message: str, **attrs: Any) -> None: ...
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cloudtoolbox
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Toolbox for the cloud.
|
|
5
|
+
Author-email: Dotz Developers <devs-dotz@dotz.com>
|
|
6
|
+
Project-URL: Repository, https://github.com/DotzInc/cloud-toolbox
|
|
7
|
+
Keywords: cloud,tools,utilities,google,gcp,amazon,aws
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Internet
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: amazon
|
|
23
|
+
Requires-Dist: boto3; extra == "amazon"
|
|
24
|
+
Provides-Extra: google
|
|
25
|
+
Requires-Dist: google-cloud-pubsub; extra == "google"
|
|
26
|
+
Requires-Dist: google-cloud-storage; extra == "google"
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: boto3; extra == "all"
|
|
29
|
+
Requires-Dist: google-cloud-pubsub; extra == "all"
|
|
30
|
+
Requires-Dist: google-cloud-storage; extra == "all"
|
|
31
|
+
|
|
32
|
+
# Cloud Toolbox
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
Decouple your applications from cloud providers with carefully crafted service interfaces.
|
|
39
|
+
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
* Python 3.8+
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
To install Cloud Toolbox, use pip:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
pip install cloudtoolbox
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Extras
|
|
53
|
+
|
|
54
|
+
Cloud Toolbox offers the following optional dependencies for easy installation of provider SDKs:
|
|
55
|
+
|
|
56
|
+
* `cloudtoolbox[amazon]` - Installs the Amazon AWS SDK.
|
|
57
|
+
* `cloudtoolbox[google]` - Installs the Google Cloud SDK.
|
|
58
|
+
* `cloudtoolbox[all]` - Installs SDKs for both providers.
|
|
59
|
+
|
|
60
|
+
## Example
|
|
61
|
+
|
|
62
|
+
Uploading a file to Google Cloud Storage.
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from cloud import factory
|
|
66
|
+
from cloud.google.storage import Uploader
|
|
67
|
+
|
|
68
|
+
FileUploader = factory.storage_uploader(Uploader)
|
|
69
|
+
|
|
70
|
+
bucket = "my-bucket"
|
|
71
|
+
filename = "notes.txt"
|
|
72
|
+
filepath = f"/path/to/{filename}"
|
|
73
|
+
|
|
74
|
+
uploader = FileUploader()
|
|
75
|
+
uploader.upload(bucket, filename, filepath)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Switching from Cloud Storage to Amazon S3.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# Replace this import
|
|
82
|
+
from cloud.google.storage import Uploader
|
|
83
|
+
|
|
84
|
+
# For this one
|
|
85
|
+
from cloud.amazon.s3 import Uploader
|
|
86
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cloudtoolbox"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Toolbox for the cloud."
|
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
|
+
authors = [{ name = "Dotz Developers", email = "devs-dotz@dotz.com" }]
|
|
11
|
+
keywords = ["cloud", "tools", "utilities", "google", "gcp", "amazon", "aws"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Operating System :: OS Independent",
|
|
14
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
15
|
+
"Programming Language :: Python :: 3.8",
|
|
16
|
+
"Programming Language :: Python :: 3.9",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Topic :: Internet",
|
|
21
|
+
"Topic :: Software Development",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
]
|
|
25
|
+
requires-python = ">=3.8"
|
|
26
|
+
dependencies = []
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Repository = "https://github.com/DotzInc/cloud-toolbox"
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
amazon = ["boto3"]
|
|
33
|
+
google = ["google-cloud-pubsub", "google-cloud-storage"]
|
|
34
|
+
all = ["boto3", "google-cloud-pubsub", "google-cloud-storage"]
|
|
35
|
+
|
|
36
|
+
[tool.ruff]
|
|
37
|
+
exclude = [".git", ".venv", ".ruff_cache"]
|
|
38
|
+
|
|
39
|
+
line-length = 100
|
|
40
|
+
indent-width = 4
|
|
41
|
+
|
|
42
|
+
[tool.ruff.lint]
|
|
43
|
+
select = ["E", "W", "F", "I", "B", "C4", "UP", "ARG001"]
|
|
44
|
+
ignore = ["E402", "E501", "W191", "B904"]
|
|
45
|
+
fixable = ["ALL"]
|
|
46
|
+
unfixable = []
|
|
47
|
+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
48
|
+
|
|
49
|
+
[tool.ruff.format]
|
|
50
|
+
quote-style = "double"
|
|
51
|
+
indent-style = "space"
|
|
52
|
+
skip-magic-trailing-comma = false
|
|
53
|
+
line-ending = "auto"
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest import mock
|
|
3
|
+
|
|
4
|
+
from cloud import factory
|
|
5
|
+
from cloud.amazon import s3, sns, sqs
|
|
6
|
+
from cloud.google import pubsub, storage
|
|
7
|
+
from cloud.protocols import MessagePublisher, StorageDownloader, StorageUploader, StorageURLSigner
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NotStorageUploader:
|
|
11
|
+
def upload_file(self):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NotStorageDownloader:
|
|
16
|
+
def download_file(self):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class NotStorageURLSigner:
|
|
21
|
+
def sign_url(self):
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DummyStorageURLSigner:
|
|
26
|
+
def generate_presigned_url(
|
|
27
|
+
self,
|
|
28
|
+
bucket_name: str,
|
|
29
|
+
source_filename: str,
|
|
30
|
+
expiration: int,
|
|
31
|
+
) -> str:
|
|
32
|
+
return ""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NotMessagePublisher:
|
|
36
|
+
def send_message(self):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestStorageUploaderFactory(unittest.TestCase):
|
|
41
|
+
@mock.patch("google.cloud.storage.Client")
|
|
42
|
+
def test_google_uploader(self, _):
|
|
43
|
+
Uploader = factory.storage_uploader(storage.Uploader)
|
|
44
|
+
uploader = Uploader()
|
|
45
|
+
|
|
46
|
+
self.assertIsInstance(uploader, StorageUploader)
|
|
47
|
+
self.assertIsInstance(uploader, storage.Uploader)
|
|
48
|
+
|
|
49
|
+
@mock.patch("boto3.client")
|
|
50
|
+
def test_amazon_uploader(self, _):
|
|
51
|
+
Uploader = factory.storage_uploader(s3.Uploader)
|
|
52
|
+
uploader = Uploader()
|
|
53
|
+
|
|
54
|
+
self.assertIsInstance(uploader, StorageUploader)
|
|
55
|
+
self.assertIsInstance(uploader, s3.Uploader)
|
|
56
|
+
|
|
57
|
+
def test_uploader_protocol_validation(self):
|
|
58
|
+
error = "NotStorageUploader does not implement StorageUploader protocol"
|
|
59
|
+
|
|
60
|
+
with self.assertRaisesRegex(AssertionError, error):
|
|
61
|
+
factory.storage_uploader(NotStorageUploader) # type: ignore
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TestStorageDownloaderFactory(unittest.TestCase):
|
|
65
|
+
@mock.patch("google.cloud.storage.Client")
|
|
66
|
+
def test_google_downloader(self, _):
|
|
67
|
+
Downloader = factory.storage_downloader(storage.Downloader)
|
|
68
|
+
downloader = Downloader()
|
|
69
|
+
|
|
70
|
+
self.assertIsInstance(downloader, StorageDownloader)
|
|
71
|
+
self.assertIsInstance(downloader, storage.Downloader)
|
|
72
|
+
|
|
73
|
+
@mock.patch("boto3.client")
|
|
74
|
+
def test_amazon_downloader(self, _):
|
|
75
|
+
Downloader = factory.storage_downloader(s3.Downloader)
|
|
76
|
+
downloader = Downloader()
|
|
77
|
+
|
|
78
|
+
self.assertIsInstance(downloader, StorageDownloader)
|
|
79
|
+
self.assertIsInstance(downloader, s3.Downloader)
|
|
80
|
+
|
|
81
|
+
def test_downloader_protocol_validation(self):
|
|
82
|
+
error = "NotStorageDownloader does not implement StorageDownloader protocol"
|
|
83
|
+
|
|
84
|
+
with self.assertRaisesRegex(AssertionError, error):
|
|
85
|
+
factory.storage_downloader(NotStorageDownloader) # type: ignore
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestStorageURLSigner(unittest.TestCase):
|
|
89
|
+
def test_urlsigner(self):
|
|
90
|
+
URLSigner = factory.storage_urlsigner(DummyStorageURLSigner)
|
|
91
|
+
urlsigner = URLSigner()
|
|
92
|
+
|
|
93
|
+
self.assertIsInstance(urlsigner, StorageURLSigner)
|
|
94
|
+
self.assertIsInstance(urlsigner, DummyStorageURLSigner)
|
|
95
|
+
|
|
96
|
+
def test_urlsigner_protocol_validation(self):
|
|
97
|
+
error = "NotStorageURLSigner does not implement StorageURLSigner protocol"
|
|
98
|
+
|
|
99
|
+
with self.assertRaisesRegex(AssertionError, error):
|
|
100
|
+
factory.storage_urlsigner(NotStorageURLSigner) # type: ignore
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class TestMessagePublisherFactory(unittest.TestCase):
|
|
104
|
+
@mock.patch("google.cloud.pubsub_v1.PublisherClient")
|
|
105
|
+
def test_google_publisher(self, _):
|
|
106
|
+
Publisher = factory.message_publisher(pubsub.Publisher)
|
|
107
|
+
publisher = Publisher()
|
|
108
|
+
|
|
109
|
+
self.assertIsInstance(publisher, MessagePublisher)
|
|
110
|
+
self.assertIsInstance(publisher, pubsub.Publisher)
|
|
111
|
+
|
|
112
|
+
@mock.patch("boto3.client")
|
|
113
|
+
def test_amazon_publisher(self, _):
|
|
114
|
+
for cls in (sns.Publisher, sqs.Publisher):
|
|
115
|
+
with self.subTest(class_name=cls.__name__):
|
|
116
|
+
Publisher = factory.message_publisher(cls)
|
|
117
|
+
publisher = Publisher()
|
|
118
|
+
|
|
119
|
+
self.assertIsInstance(publisher, MessagePublisher)
|
|
120
|
+
self.assertIsInstance(publisher, cls)
|
|
121
|
+
|
|
122
|
+
def test_publisher_protocol_validation(self):
|
|
123
|
+
error = "NotMessagePublisher does not implement MessagePublisher protocol"
|
|
124
|
+
|
|
125
|
+
with self.assertRaisesRegex(AssertionError, error):
|
|
126
|
+
factory.message_publisher(NotMessagePublisher) # type: ignore
|
cloudtoolbox-0.1.0/PKG-INFO
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: cloudtoolbox
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Toolbox for the cloud.
|
|
5
|
-
Author-email: Dotz Developers <devs-dotz@dotz.com>
|
|
6
|
-
Keywords: cloud,tools,utilities,google,gcp,amazon,aws
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Requires-Python: >=3.8
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Provides-Extra: amazon
|
|
12
|
-
Requires-Dist: boto3; extra == "amazon"
|
|
13
|
-
Provides-Extra: google
|
|
14
|
-
Requires-Dist: google-cloud-pubsub; extra == "google"
|
|
15
|
-
Requires-Dist: google-cloud-storage; extra == "google"
|
|
16
|
-
|
|
17
|
-
# Cloud Toolbox
|
|
18
|
-
|
|
19
|
-
Decouple your applications from cloud providers with carefully crafted service interfaces.
|
cloudtoolbox-0.1.0/README.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
import boto3
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Uploader:
|
|
7
|
-
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
8
|
-
self.client = boto3.client("s3", *args, **kwargs)
|
|
9
|
-
|
|
10
|
-
def upload(self, bucket_name: str, destination_filename: str, source_filename: str) -> None:
|
|
11
|
-
self.client.upload_file(source_filename, bucket_name, destination_filename)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
from typing import Any, Callable, Type
|
|
2
|
-
|
|
3
|
-
from cloud.protocols import MessagePublisher, StorageUploader
|
|
4
|
-
|
|
5
|
-
error_message = "%(class)s does not implement %(protocol)s protocol"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def storage_uploader(
|
|
9
|
-
uploader_class: Type[StorageUploader], *args: Any, **kwargs: Any
|
|
10
|
-
) -> Callable[[], StorageUploader]:
|
|
11
|
-
error = error_message % {"class": uploader_class.__name__, "protocol": "StorageUploader"}
|
|
12
|
-
assert issubclass(uploader_class, StorageUploader), error
|
|
13
|
-
|
|
14
|
-
def maker() -> StorageUploader:
|
|
15
|
-
return uploader_class(*args, **kwargs)
|
|
16
|
-
|
|
17
|
-
return maker
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def message_publisher(
|
|
21
|
-
publisher_class: Type[MessagePublisher], *args: Any, **kwargs: Any
|
|
22
|
-
) -> Callable[[], MessagePublisher]:
|
|
23
|
-
error = error_message % {"class": publisher_class.__name__, "protocol": "MessagePublisher"}
|
|
24
|
-
assert issubclass(publisher_class, MessagePublisher), error
|
|
25
|
-
|
|
26
|
-
def maker() -> MessagePublisher:
|
|
27
|
-
return publisher_class(*args, **kwargs)
|
|
28
|
-
|
|
29
|
-
return maker
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from google.cloud import storage
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Uploader:
|
|
7
|
-
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
8
|
-
self.client = storage.Client(*args, **kwargs)
|
|
9
|
-
|
|
10
|
-
def upload(self, bucket_name: str, destination_filename: str, source_filename: str) -> None:
|
|
11
|
-
bucket = self.client.bucket(bucket_name)
|
|
12
|
-
blob = bucket.blob(destination_filename)
|
|
13
|
-
blob.upload_from_filename(source_filename)
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from typing import Any, Protocol, runtime_checkable
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
@runtime_checkable
|
|
5
|
-
class StorageUploader(Protocol):
|
|
6
|
-
def upload(self, bucket_name: str, destination_filename: str, source_filename: str) -> None: ...
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@runtime_checkable
|
|
10
|
-
class MessagePublisher(Protocol):
|
|
11
|
-
def publish(self, recipient: str, message: str, **attrs: Any) -> None: ...
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: cloudtoolbox
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Toolbox for the cloud.
|
|
5
|
-
Author-email: Dotz Developers <devs-dotz@dotz.com>
|
|
6
|
-
Keywords: cloud,tools,utilities,google,gcp,amazon,aws
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Requires-Python: >=3.8
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Provides-Extra: amazon
|
|
12
|
-
Requires-Dist: boto3; extra == "amazon"
|
|
13
|
-
Provides-Extra: google
|
|
14
|
-
Requires-Dist: google-cloud-pubsub; extra == "google"
|
|
15
|
-
Requires-Dist: google-cloud-storage; extra == "google"
|
|
16
|
-
|
|
17
|
-
# Cloud Toolbox
|
|
18
|
-
|
|
19
|
-
Decouple your applications from cloud providers with carefully crafted service interfaces.
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "cloudtoolbox"
|
|
7
|
-
version = "0.1.0"
|
|
8
|
-
description = "Toolbox for the cloud."
|
|
9
|
-
readme = {file = "README.md", content-type = "text/markdown"}
|
|
10
|
-
authors = [
|
|
11
|
-
{name = "Dotz Developers", email = "devs-dotz@dotz.com"},
|
|
12
|
-
]
|
|
13
|
-
keywords = ["cloud", "tools", "utilities", "google", "gcp", "amazon", "aws"]
|
|
14
|
-
classifiers = [
|
|
15
|
-
"Programming Language :: Python :: 3",
|
|
16
|
-
]
|
|
17
|
-
requires-python = ">=3.8"
|
|
18
|
-
dependencies = []
|
|
19
|
-
|
|
20
|
-
[project.optional-dependencies]
|
|
21
|
-
amazon = ["boto3"]
|
|
22
|
-
google = ["google-cloud-pubsub", "google-cloud-storage"]
|
|
23
|
-
|
|
24
|
-
[tool.ruff]
|
|
25
|
-
exclude = [
|
|
26
|
-
".git",
|
|
27
|
-
".venv",
|
|
28
|
-
".ruff_cache",
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
line-length = 100
|
|
32
|
-
indent-width = 4
|
|
33
|
-
|
|
34
|
-
[tool.ruff.lint]
|
|
35
|
-
select = ["E", "W", "F", "I", "B", "C4", "UP","ARG001"]
|
|
36
|
-
ignore = ["E402", "E501", "W191", "B904"]
|
|
37
|
-
fixable = ["ALL"]
|
|
38
|
-
unfixable = []
|
|
39
|
-
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
40
|
-
|
|
41
|
-
[tool.ruff.format]
|
|
42
|
-
quote-style = "double"
|
|
43
|
-
indent-style = "space"
|
|
44
|
-
skip-magic-trailing-comma = false
|
|
45
|
-
line-ending = "auto"
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from unittest import mock
|
|
3
|
-
|
|
4
|
-
from cloud import factory
|
|
5
|
-
from cloud.amazon import s3
|
|
6
|
-
from cloud.google import pubsub, storage
|
|
7
|
-
from cloud.protocols import MessagePublisher, StorageUploader
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class NotStorageUploader:
|
|
11
|
-
def upload_file(self):
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class NotMessagePublisher:
|
|
16
|
-
def send_message(self):
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class TestStorageUploaderFactory(unittest.TestCase):
|
|
21
|
-
@mock.patch("google.cloud.storage.Client")
|
|
22
|
-
def test_google_uploader(self, _):
|
|
23
|
-
Uploader = factory.storage_uploader(storage.Uploader)
|
|
24
|
-
uploader = Uploader()
|
|
25
|
-
|
|
26
|
-
self.assertIsInstance(uploader, StorageUploader)
|
|
27
|
-
self.assertIsInstance(uploader, storage.Uploader)
|
|
28
|
-
|
|
29
|
-
@mock.patch("boto3.client")
|
|
30
|
-
def test_amazon_uploader(self, _):
|
|
31
|
-
Uploader = factory.storage_uploader(s3.Uploader)
|
|
32
|
-
uploader = Uploader()
|
|
33
|
-
|
|
34
|
-
self.assertIsInstance(uploader, StorageUploader)
|
|
35
|
-
self.assertIsInstance(uploader, s3.Uploader)
|
|
36
|
-
|
|
37
|
-
def test_uploader_protocol_validation(self):
|
|
38
|
-
error = "NotStorageUploader does not implement StorageUploader protocol"
|
|
39
|
-
|
|
40
|
-
with self.assertRaisesRegex(AssertionError, error):
|
|
41
|
-
factory.storage_uploader(NotStorageUploader) # type: ignore
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class TestMessagePublisherFactory(unittest.TestCase):
|
|
45
|
-
@mock.patch("google.cloud.pubsub_v1.PublisherClient")
|
|
46
|
-
def test_google_publisher(self, _):
|
|
47
|
-
Publisher = factory.message_publisher(pubsub.Publisher)
|
|
48
|
-
publisher = Publisher()
|
|
49
|
-
|
|
50
|
-
self.assertIsInstance(publisher, MessagePublisher)
|
|
51
|
-
self.assertIsInstance(publisher, pubsub.Publisher)
|
|
52
|
-
|
|
53
|
-
def test_publisher_protocol_validation(self):
|
|
54
|
-
error = "NotMessagePublisher does not implement MessagePublisher protocol"
|
|
55
|
-
|
|
56
|
-
with self.assertRaisesRegex(AssertionError, error):
|
|
57
|
-
factory.message_publisher(NotMessagePublisher) # type: ignore
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|