bifrostsdk 1.0.0__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.
- bifrostsdk-1.0.0.dist-info/LICENSE +21 -0
- bifrostsdk-1.0.0.dist-info/METADATA +124 -0
- bifrostsdk-1.0.0.dist-info/RECORD +48 -0
- bifrostsdk-1.0.0.dist-info/WHEEL +5 -0
- bifrostsdk-1.0.0.dist-info/top_level.txt +1 -0
- byfrost/__init__.py +46 -0
- byfrost/__init__.pyi +81 -0
- byfrost/bifrost.py +148 -0
- byfrost/bifrost.pyi +36 -0
- byfrost/gcs/__init__.py +3 -0
- byfrost/gcs/__init__.pyi +3 -0
- byfrost/gcs/gcs.py +189 -0
- byfrost/gcs/gcs.pyi +65 -0
- byfrost/pinata/__init__.py +0 -0
- byfrost/pinata/__init__.pyi +0 -0
- byfrost/pinata/pinata.py +221 -0
- byfrost/pinata/pinata.pyi +54 -0
- byfrost/s3/__init__.py +0 -0
- byfrost/s3/__init__.pyi +0 -0
- byfrost/s3/s3.py +188 -0
- byfrost/s3/s3.pyi +65 -0
- byfrost/shared/__init__.py +3 -0
- byfrost/shared/config/__init__.py +29 -0
- byfrost/shared/config/__init__.pyi +29 -0
- byfrost/shared/config/option.py +21 -0
- byfrost/shared/config/provider.py +22 -0
- byfrost/shared/config/request.py +24 -0
- byfrost/shared/config/url.py +24 -0
- byfrost/shared/errors/__init__.py +16 -0
- byfrost/shared/errors/__init__.pyi +16 -0
- byfrost/shared/errors/color.py +18 -0
- byfrost/shared/errors/constant.py +30 -0
- byfrost/shared/errors/interface.py +21 -0
- byfrost/shared/errors/interface.pyi +21 -0
- byfrost/shared/errors/loga.py +28 -0
- byfrost/shared/errors/loga.pyi +21 -0
- byfrost/shared/request/__init__.py +1 -0
- byfrost/shared/request/__init__.pyi +1 -0
- byfrost/shared/request/builder.py +51 -0
- byfrost/shared/types/__init__.py +1 -0
- byfrost/shared/types/dataclass/__init__.py +4 -0
- byfrost/shared/types/dataclass/__init__.pyi +4 -0
- byfrost/shared/types/dataclass/bridge.py +155 -0
- byfrost/shared/types/dataclass/file.py +222 -0
- byfrost/shared/types/typeddict/__init__.py +12 -0
- byfrost/shared/types/typeddict/__init__.pyi +12 -0
- byfrost/shared/types/typeddict/bridge.py +85 -0
- byfrost/shared/types/typeddict/file.py +203 -0
byfrost/gcs/gcs.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""Bifrost interface for Google Cloud Storage"""
|
|
4
|
+
|
|
5
|
+
from byfrost.shared import errors
|
|
6
|
+
from byfrost.shared.config import provider
|
|
7
|
+
from google.cloud import storage
|
|
8
|
+
from ..shared.types.dataclass import file as bfile
|
|
9
|
+
from ..shared.types.dataclass import bridge
|
|
10
|
+
from typing import List, Tuple
|
|
11
|
+
from ..shared.errors.interface import BifrostError
|
|
12
|
+
from ..shared.config import option
|
|
13
|
+
from ..shared.errors import loga
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GoogleCloudStorage:
|
|
19
|
+
def __init__(self, bc: bridge.BridgeConfig, client: storage.Client):
|
|
20
|
+
self.provider = provider.providers[bc.provider]
|
|
21
|
+
self.default_bucket = bc.default_bucket
|
|
22
|
+
self.credentials_file = bc.credentials_file
|
|
23
|
+
self.project = bc.project
|
|
24
|
+
self.default_timeout = bc.default_timeout
|
|
25
|
+
self.client = client
|
|
26
|
+
self.enable_debug = bc.enable_debug
|
|
27
|
+
self.public_read = bc.public_read
|
|
28
|
+
self.use_async = bc.use_async
|
|
29
|
+
|
|
30
|
+
def upload_file(
|
|
31
|
+
self, file_face: bfile.File
|
|
32
|
+
) -> Tuple[bfile.UploadedFile, BifrostError]:
|
|
33
|
+
"""upload_file uploads a file to Google Cloud Storage and returns an error if one occurs."""
|
|
34
|
+
if file_face is None:
|
|
35
|
+
return None, BifrostError("file is none", errors.ErrBadRequest)
|
|
36
|
+
|
|
37
|
+
# verify that the file is derived from File
|
|
38
|
+
if not isinstance(file_face, bfile.File):
|
|
39
|
+
return None, BifrostError(
|
|
40
|
+
"invalid file type: {}".format(type(file_face)), errors.ErrBadRequest
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# verify that the file has a valid path
|
|
44
|
+
if file_face.path is None or file_face.path == "":
|
|
45
|
+
return None, BifrostError("no path specified", errors.ErrBadRequest)
|
|
46
|
+
|
|
47
|
+
if file_face.filename is None or file_face.filename == "":
|
|
48
|
+
file_face.filename = os.path.basename(file_face.path)
|
|
49
|
+
|
|
50
|
+
# verify that the file has a valid options
|
|
51
|
+
if file_face.options is None:
|
|
52
|
+
file_face.options = bfile.Options()
|
|
53
|
+
|
|
54
|
+
# verify the connection
|
|
55
|
+
if not self.is_connected():
|
|
56
|
+
return None, BifrostError(
|
|
57
|
+
"no active Google Cloud Storage client", errors.ErrClientError
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# verify that the file has a valid acl
|
|
61
|
+
if (
|
|
62
|
+
file_face.options.acl is None
|
|
63
|
+
or file_face.options.acl == ""
|
|
64
|
+
and self.public_read
|
|
65
|
+
):
|
|
66
|
+
file_face.options.acl = option.ACLPublicRead
|
|
67
|
+
|
|
68
|
+
# verify that the file has a valid metadata
|
|
69
|
+
if file_face.options.metadata is None:
|
|
70
|
+
file_face.options.metadata = {}
|
|
71
|
+
|
|
72
|
+
# upload file to Google Cloud Storage
|
|
73
|
+
bucket = self.client.bucket(self.default_bucket)
|
|
74
|
+
|
|
75
|
+
blob = bucket.blob(file_face.filename)
|
|
76
|
+
blob.metadata = file_face.options.metadata
|
|
77
|
+
blob.upload_from_filename(file_face.path)
|
|
78
|
+
|
|
79
|
+
# configure upload options
|
|
80
|
+
if file_face.options.acl == option.ACLPublicRead:
|
|
81
|
+
blob.make_public()
|
|
82
|
+
elif file_face.options.acl == option.ACLPrivate:
|
|
83
|
+
blob.make_private()
|
|
84
|
+
|
|
85
|
+
# return the uploaded file
|
|
86
|
+
#
|
|
87
|
+
return (
|
|
88
|
+
bfile.UploadedFile(
|
|
89
|
+
name=file_face.filename,
|
|
90
|
+
bucket=self.default_bucket,
|
|
91
|
+
path=file_face.path,
|
|
92
|
+
size=blob.size,
|
|
93
|
+
url=blob.public_url,
|
|
94
|
+
preview=blob.public_url,
|
|
95
|
+
provider_object=blob,
|
|
96
|
+
),
|
|
97
|
+
None,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def upload_multi_file(
|
|
101
|
+
self,
|
|
102
|
+
multi_face: bfile.MultiFile,
|
|
103
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
104
|
+
"""upload multi file uploads multiple files to Google Cloud Storage and returns an error if one occurs."""
|
|
105
|
+
if multi_face is None:
|
|
106
|
+
return None, BifrostError("multi file is none", errors.ErrBadRequest)
|
|
107
|
+
|
|
108
|
+
# verify that the multi file is derived from MultiFile
|
|
109
|
+
if not isinstance(multi_face, bfile.MultiFile):
|
|
110
|
+
return None, BifrostError(
|
|
111
|
+
"invalid multi file type: {}".format(type(multi_face)),
|
|
112
|
+
errors.ErrBadRequest,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# verify that the multi file has a valid files
|
|
116
|
+
if multi_face.files is None or len(multi_face.files) == 0:
|
|
117
|
+
return None, BifrostError("no files specified", errors.ErrBadRequest)
|
|
118
|
+
|
|
119
|
+
# verify the connection
|
|
120
|
+
if not self.is_connected():
|
|
121
|
+
return None, BifrostError(
|
|
122
|
+
"no active Google Cloud Storage client", errors.ErrClientError
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# upload files to Google Cloud Storage
|
|
126
|
+
uploaded_files = []
|
|
127
|
+
|
|
128
|
+
for file_face in multi_face.files:
|
|
129
|
+
# verify that the multi file has a valid global options
|
|
130
|
+
if multi_face.global_options is not None:
|
|
131
|
+
# for each option in the global option dataclass, if it is not present in the file option dataclass, then add it to the file option dataclass
|
|
132
|
+
for option in multi_face.global_options.__dataclass_fields__:
|
|
133
|
+
if not hasattr(file_face.options, option):
|
|
134
|
+
setattr(
|
|
135
|
+
file_face.options,
|
|
136
|
+
option,
|
|
137
|
+
getattr(multi_face.global_options, option),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
uploaded_file, err = self.upload_file(file_face)
|
|
141
|
+
|
|
142
|
+
if err is not None:
|
|
143
|
+
if self.enable_debug:
|
|
144
|
+
loga.error(
|
|
145
|
+
"Upload for file at path %s failed with err: %s",
|
|
146
|
+
file_face.path,
|
|
147
|
+
err.message,
|
|
148
|
+
)
|
|
149
|
+
uploaded_files.append(
|
|
150
|
+
bfile.UploadedFile(
|
|
151
|
+
error=err, name=file_face.filename, path=file_face.path
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
continue
|
|
155
|
+
uploaded_files.append(uploaded_file)
|
|
156
|
+
return uploaded_files, None
|
|
157
|
+
|
|
158
|
+
def disconnect(self) -> BifrostError:
|
|
159
|
+
"""disconnect closes the Google Cloud Storage client connection and returns an error if one occurs."""
|
|
160
|
+
if self.client is None:
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
self.client.close()
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def config(self) -> bridge.BridgeConfig:
|
|
167
|
+
"""config returns the provider configuration."""
|
|
168
|
+
return bridge.BridgeConfig(
|
|
169
|
+
provider=self.provider,
|
|
170
|
+
zone=self.zone,
|
|
171
|
+
default_bucket=self.default_bucket,
|
|
172
|
+
credentials_file=self.credentials_file,
|
|
173
|
+
project=self.project,
|
|
174
|
+
default_timeout=self.default_timeout,
|
|
175
|
+
enable_debug=self.enable_debug,
|
|
176
|
+
public_read=self.public_read,
|
|
177
|
+
use_async=self.use_async,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def is_connected(self) -> bool:
|
|
181
|
+
"""is_connected returns true if there is an active connection to the provider."""
|
|
182
|
+
return self.client is not None
|
|
183
|
+
|
|
184
|
+
def upload_folder(
|
|
185
|
+
self,
|
|
186
|
+
fold_face: bfile.MultiFile,
|
|
187
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
188
|
+
"""upload_folder uploads a folder to the Google Cloud Storage and returns an error if one occurs."""
|
|
189
|
+
...
|
byfrost/gcs/gcs.pyi
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
The RainbowBridge interface for Google Cloud Storage
|
|
4
|
+
|
|
5
|
+
All providers must implement this interface completely
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from ..shared.types.dataclass import file as bfile
|
|
9
|
+
from ..shared.types.dataclass import bridge
|
|
10
|
+
from typing import List, Tuple
|
|
11
|
+
from ..shared.errors.interface import BifrostError
|
|
12
|
+
from google.cloud import storage
|
|
13
|
+
|
|
14
|
+
class GoogleCloudStorage:
|
|
15
|
+
"""GoogleCloudStorage is the Google Cloud Storage class"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, bc: bridge.BridgeConfig, client: storage.Client):
|
|
18
|
+
"""__init__ initializes the GoogleCloudStorage class."""
|
|
19
|
+
...
|
|
20
|
+
def upload_file(
|
|
21
|
+
self, file_face: bfile.File
|
|
22
|
+
) -> Tuple[bfile.UploadedFile, BifrostError]:
|
|
23
|
+
"""
|
|
24
|
+
upload_file uploads a file to the provider storage and returns an error if one occurs.
|
|
25
|
+
|
|
26
|
+
Note: for some providers, upload_file requires that a default bucket be set in bifrosbfile.BridgeConfig.
|
|
27
|
+
"""
|
|
28
|
+
...
|
|
29
|
+
def upload_multi_file(
|
|
30
|
+
self,
|
|
31
|
+
multi_face: bfile.MultiFile,
|
|
32
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
33
|
+
"""
|
|
34
|
+
upload_multi_file uploads mutliple files to the provider storage and returns an error if one occurs. If any of the uploads fail, the error is appended to the []UploadedFile.Error and also logged when debug is enabled while the rest of the uploads continue.
|
|
35
|
+
|
|
36
|
+
Note: for some providers, UploadMultiFile requires that a default bucket be set in bifrosbfile.BridgeConfig.
|
|
37
|
+
"""
|
|
38
|
+
...
|
|
39
|
+
def disconnect(self) -> BifrostError:
|
|
40
|
+
"""
|
|
41
|
+
disconnect closes the provider client connection and returns an error if one occurs.
|
|
42
|
+
|
|
43
|
+
Disconnect should only be called when the connection is no longer needed.
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
def config(self) -> bridge.BridgeConfig:
|
|
47
|
+
"""
|
|
48
|
+
config returns the provider configuration.
|
|
49
|
+
"""
|
|
50
|
+
...
|
|
51
|
+
def is_connected(self) -> bool:
|
|
52
|
+
"""
|
|
53
|
+
is_connected returns true if there is an active connection to the provider.
|
|
54
|
+
"""
|
|
55
|
+
...
|
|
56
|
+
def upload_folder(
|
|
57
|
+
self,
|
|
58
|
+
fold_face: bfile.MultiFile,
|
|
59
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
60
|
+
"""
|
|
61
|
+
upload_folder uploads a folder to the provider storage and returns an error if one occurs.
|
|
62
|
+
|
|
63
|
+
Note: for some providers, upload_folder requires that a default bucket be set in bifrosbfile.BridgeConfig.
|
|
64
|
+
"""
|
|
65
|
+
...
|
|
File without changes
|
|
File without changes
|
byfrost/pinata/pinata.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Bifrost interface for Pinata Cloud."""
|
|
2
|
+
|
|
3
|
+
from byfrost.shared import errors
|
|
4
|
+
from byfrost.shared.config import provider
|
|
5
|
+
from ..shared.types.dataclass import file as bfile
|
|
6
|
+
from ..shared.types.dataclass import bridge
|
|
7
|
+
from typing import List, Tuple
|
|
8
|
+
from ..shared.errors.interface import BifrostError
|
|
9
|
+
from ..shared.config import option, request, url
|
|
10
|
+
from ..shared.errors import loga
|
|
11
|
+
from ..shared.request.builder import Client, new_client
|
|
12
|
+
import os
|
|
13
|
+
import requests
|
|
14
|
+
import json
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PinataCloud:
|
|
18
|
+
def __init__(self, bc: bridge.BridgeConfig, client: Client):
|
|
19
|
+
self.provider = provider.providers[bc.provider]
|
|
20
|
+
self.default_bucket = bc.default_bucket
|
|
21
|
+
self.pinata_jwt = bc.pinata_jwt
|
|
22
|
+
self.default_timeout = bc.default_timeout
|
|
23
|
+
self.client = client
|
|
24
|
+
self.enable_debug = bc.enable_debug
|
|
25
|
+
self.public_read = bc.public_read
|
|
26
|
+
self.use_async = bc.use_async
|
|
27
|
+
|
|
28
|
+
def upload_file(
|
|
29
|
+
self, file_face: bfile.File
|
|
30
|
+
) -> Tuple[bfile.UploadedFile, BifrostError]:
|
|
31
|
+
"""upload_file uploads a file to Pinata Storage and returns an error if one occurs."""
|
|
32
|
+
if file_face is None:
|
|
33
|
+
return None, BifrostError("file is none", errors.ErrBadRequest)
|
|
34
|
+
|
|
35
|
+
# verify that the file is derived from File
|
|
36
|
+
if not isinstance(file_face, bfile.File):
|
|
37
|
+
return None, BifrostError(
|
|
38
|
+
"invalid file type: {}".format(type(file_face)), errors.ErrBadRequest
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# verify that the file has a valid path
|
|
42
|
+
if file_face.path is None or file_face.path == "":
|
|
43
|
+
return None, BifrostError("no path specified", errors.ErrBadRequest)
|
|
44
|
+
|
|
45
|
+
if not os.path.exists(file_face.path):
|
|
46
|
+
raise BifrostError(
|
|
47
|
+
f"file does not exist: {file_face.path}", errors.ErrBadRequest
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if file_face.filename is None or file_face.filename == "":
|
|
51
|
+
file_face.filename = os.path.basename(file_face.path)
|
|
52
|
+
|
|
53
|
+
# verify that the file has a valid options
|
|
54
|
+
if file_face.options is None:
|
|
55
|
+
file_face.options = bfile.Options()
|
|
56
|
+
|
|
57
|
+
# verify that the file has a valid metadata
|
|
58
|
+
if file_face.options.metadata is None:
|
|
59
|
+
file_face.options.metadata = {}
|
|
60
|
+
|
|
61
|
+
# verify the connection
|
|
62
|
+
if not self.is_connected():
|
|
63
|
+
return None, BifrostError(
|
|
64
|
+
"no active Pinata Storage client", errors.ErrClientError
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
param = bfile.Param(
|
|
68
|
+
files=[
|
|
69
|
+
bfile.ParamFile(
|
|
70
|
+
path=file_face.path,
|
|
71
|
+
key="file",
|
|
72
|
+
name=file_face.filename,
|
|
73
|
+
)
|
|
74
|
+
],
|
|
75
|
+
data=[],
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Configure upload options
|
|
79
|
+
for k, v in file_face.options.__dataclass_fields__.items():
|
|
80
|
+
if k == option.OptPinata:
|
|
81
|
+
try:
|
|
82
|
+
opt = json.dumps(v)
|
|
83
|
+
param.data.append(bfile.ParamData(key=OptPinata, value=opt))
|
|
84
|
+
except json.JSONDecodeError as e:
|
|
85
|
+
return None, BifrostError(
|
|
86
|
+
f"failed to parse pinata options: {str(e)}",
|
|
87
|
+
errors.ErrBadRequest,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
elif k == provider.PinataCloud + option.OptMetadata.capitalize():
|
|
91
|
+
try:
|
|
92
|
+
m = json.dumps(v)
|
|
93
|
+
param.data.append(bfile.ParamData(key=k, value=m))
|
|
94
|
+
except json.JSONDecodeError as e:
|
|
95
|
+
return None, BifrostError(
|
|
96
|
+
f"failed to parse pinata metadata: {str(e)}",
|
|
97
|
+
errors.ErrBadRequest,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
response, error = self.client.post_form(url.URLPinataPinFile, param)
|
|
101
|
+
|
|
102
|
+
if error is not None:
|
|
103
|
+
print(error)
|
|
104
|
+
return None, BifrostError("failed to upload file", errors.ErrBadRequest)
|
|
105
|
+
|
|
106
|
+
if "Error" in response and response["Error"] != "":
|
|
107
|
+
return None, BifrostError(
|
|
108
|
+
f"failed to upload file: {response['Error']}", errors.ErrBadRequest
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
bfile.UploadedFile(
|
|
113
|
+
size=response["PinSize"],
|
|
114
|
+
cid=response["IpfsHash"],
|
|
115
|
+
preview=url.URLPinataGateway.format(response["IpfsHash"]),
|
|
116
|
+
provider_object=response,
|
|
117
|
+
name=os.path.basename(file_face.path),
|
|
118
|
+
path=file_face.path,
|
|
119
|
+
url=url.URLPinataGateway.format(response["IpfsHash"]),
|
|
120
|
+
),
|
|
121
|
+
None,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def upload_multi_file(
|
|
125
|
+
self,
|
|
126
|
+
multi_face: bfile.MultiFile,
|
|
127
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
128
|
+
"""upload multi file uploads multiple files to Pinata Storage and returns an error if one occurs."""
|
|
129
|
+
if multi_face is None:
|
|
130
|
+
return None, BifrostError("multi file is none", errors.ErrBadRequest)
|
|
131
|
+
|
|
132
|
+
# verify that the multi file is derived from MultiFile
|
|
133
|
+
if not isinstance(multi_face, bfile.MultiFile):
|
|
134
|
+
return None, BifrostError(
|
|
135
|
+
"invalid multi file type: {}".format(type(multi_face)),
|
|
136
|
+
errors.ErrBadRequest,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# verify that the multi file has a valid files
|
|
140
|
+
if multi_face.files is None or len(multi_face.files) == 0:
|
|
141
|
+
return None, BifrostError("no files specified", errors.ErrBadRequest)
|
|
142
|
+
|
|
143
|
+
# verify the connection
|
|
144
|
+
if not self.is_connected():
|
|
145
|
+
return None, BifrostError(
|
|
146
|
+
"no active Pinata Cloud client", errors.ErrClientError
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# upload files to Google Cloud Storage
|
|
150
|
+
uploaded_files = []
|
|
151
|
+
|
|
152
|
+
for file_face in multi_face.files:
|
|
153
|
+
# verify that the multi file has a valid global options
|
|
154
|
+
if multi_face.global_options is not None:
|
|
155
|
+
# for each option in the global option dataclass, if it is not present in the file option dataclass, then add it to the file option dataclass
|
|
156
|
+
for option in multi_face.global_options.__dataclass_fields__:
|
|
157
|
+
if not hasattr(file_face.options, option):
|
|
158
|
+
setattr(
|
|
159
|
+
file_face.options,
|
|
160
|
+
option,
|
|
161
|
+
getattr(multi_face.global_options, option),
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
uploaded_file, err = self.upload_file(file_face)
|
|
165
|
+
|
|
166
|
+
if err is not None:
|
|
167
|
+
if self.enable_debug:
|
|
168
|
+
loga.error(
|
|
169
|
+
"Upload for file at path %s failed with err: %s",
|
|
170
|
+
file_face.path,
|
|
171
|
+
err.message,
|
|
172
|
+
)
|
|
173
|
+
uploaded_files.append(
|
|
174
|
+
bfile.UploadedFile(
|
|
175
|
+
error=err, name=file_face.filename, path=file_face.path
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
continue
|
|
179
|
+
uploaded_files.append(uploaded_file)
|
|
180
|
+
return uploaded_files, None
|
|
181
|
+
|
|
182
|
+
def preflight(self) -> BifrostError:
|
|
183
|
+
"""preflight attempts to authenticate with Pinata and returns an error if one occurs."""
|
|
184
|
+
try:
|
|
185
|
+
req = requests.Request(
|
|
186
|
+
request.MethodGet,
|
|
187
|
+
url.URLPinataAuth,
|
|
188
|
+
headers=self.client.session.headers,
|
|
189
|
+
).prepare()
|
|
190
|
+
res = self.client.session.send(req)
|
|
191
|
+
if res.json()["message"] == "":
|
|
192
|
+
return BifrostError(res.json()["error"], errors.ErrUnauthorized)
|
|
193
|
+
return None
|
|
194
|
+
except Exception as e:
|
|
195
|
+
return BifrostError(str(e), errors.ErrClientError)
|
|
196
|
+
|
|
197
|
+
def disconnect(self) -> BifrostError:
|
|
198
|
+
"""disconnect closes the Pinata Storage client connection and returns an error if one occurs."""
|
|
199
|
+
if self.client is None:
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
def config(self) -> bridge.BridgeConfig:
|
|
203
|
+
"""config returns the provider configuration."""
|
|
204
|
+
return bridge.BridgeConfig(
|
|
205
|
+
provider=self.provider,
|
|
206
|
+
default_timeout=self.default_timeout,
|
|
207
|
+
enable_debug=self.enable_debug,
|
|
208
|
+
public_read=self.public_read,
|
|
209
|
+
use_async=self.use_async,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def is_connected(self) -> bool:
|
|
213
|
+
"""is_connected returns true if there is an active connection to the provider."""
|
|
214
|
+
return self.client is not None
|
|
215
|
+
|
|
216
|
+
def upload_folder(
|
|
217
|
+
self,
|
|
218
|
+
fold_face: bfile.MultiFile,
|
|
219
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
220
|
+
"""upload_folder uploads a folder to Pinata Storage and returns an error if one occurs."""
|
|
221
|
+
...
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
The RainbowBridge interface for Pinata Cloud
|
|
4
|
+
|
|
5
|
+
All providers must implement this interface completely
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
"""Bifrost interface for Pinata Cloud."""
|
|
9
|
+
|
|
10
|
+
from byfrost.shared import errors
|
|
11
|
+
from byfrost.shared.config import provider
|
|
12
|
+
from ..shared.types.dataclass import file as bfile
|
|
13
|
+
from ..shared.types.dataclass import bridge
|
|
14
|
+
from typing import List, Tuple
|
|
15
|
+
from ..shared.errors.interface import BifrostError
|
|
16
|
+
from ..shared.config import option, request, url
|
|
17
|
+
from ..shared.errors import loga
|
|
18
|
+
from ..shared.request.builder import Client
|
|
19
|
+
|
|
20
|
+
class PinataCloud:
|
|
21
|
+
"""PinataCloud is the Google Cloud Storage class"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, bc: bridge.BridgeConfig, client: Client):
|
|
24
|
+
"""__init__ initializes the GoogleCloudStorage class."""
|
|
25
|
+
...
|
|
26
|
+
def upload_file(
|
|
27
|
+
self, file_face: bfile.File
|
|
28
|
+
) -> Tuple[bfile.UploadedFile, BifrostError]:
|
|
29
|
+
"""upload_file uploads a file to Pinata Storage and returns an error if one occurs."""
|
|
30
|
+
...
|
|
31
|
+
def upload_multi_file(
|
|
32
|
+
self,
|
|
33
|
+
multi_face: bfile.MultiFile,
|
|
34
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
35
|
+
"""upload multi file uploads multiple files to Pinata Storage and returns an error if one occurs."""
|
|
36
|
+
...
|
|
37
|
+
def preflight(self) -> BifrostError:
|
|
38
|
+
"""preflight attempts to authenticate with Pinata and returns an error if one occurs."""
|
|
39
|
+
...
|
|
40
|
+
def disconnect(self) -> BifrostError:
|
|
41
|
+
"""disconnect closes the Pinata Storage client connection and returns an error if one occurs."""
|
|
42
|
+
...
|
|
43
|
+
def config(self) -> bridge.BridgeConfig:
|
|
44
|
+
"""config returns the provider configuration."""
|
|
45
|
+
...
|
|
46
|
+
def is_connected(self) -> bool:
|
|
47
|
+
"""is_connected returns true if there is an active connection to the provider."""
|
|
48
|
+
...
|
|
49
|
+
def upload_folder(
|
|
50
|
+
self,
|
|
51
|
+
fold_face: bfile.MultiFile,
|
|
52
|
+
) -> Tuple[List[bfile.UploadedFile], BifrostError]:
|
|
53
|
+
"""upload_folder uploads a folder to Pinata Storage and returns an error if one occurs."""
|
|
54
|
+
...
|
byfrost/s3/__init__.py
ADDED
|
File without changes
|
byfrost/s3/__init__.pyi
ADDED
|
File without changes
|