vaultsens-sdk 0.1.1__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.
- vaultsens_sdk-0.1.1/PKG-INFO +54 -0
- vaultsens_sdk-0.1.1/README.md +39 -0
- vaultsens_sdk-0.1.1/pyproject.toml +27 -0
- vaultsens_sdk-0.1.1/setup.cfg +4 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk/__init__.py +3 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk/client.py +199 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk.egg-info/PKG-INFO +54 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk.egg-info/SOURCES.txt +9 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk.egg-info/dependency_links.txt +1 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk.egg-info/requires.txt +1 -0
- vaultsens_sdk-0.1.1/vaultsens_sdk.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vaultsens-sdk
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: VaultSens SDK for API key uploads and file management
|
|
5
|
+
Author: VaultSens
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://vaultsens.com/
|
|
8
|
+
Project-URL: Repository, https://github.com/vaultsens/vaultsens-sdk-python
|
|
9
|
+
Keywords: vaultsens,sdk,storage,upload
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: requests>=2.31
|
|
15
|
+
|
|
16
|
+
# vaultsens-sdk
|
|
17
|
+
|
|
18
|
+
Python SDK for VaultSens. API key + secret authentication with file upload and management helpers.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install vaultsens-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from vaultsens_sdk import VaultSensClient
|
|
30
|
+
|
|
31
|
+
client = VaultSensClient(
|
|
32
|
+
base_url="https://api.vaultsens.com",
|
|
33
|
+
api_key="fs_xxx",
|
|
34
|
+
api_secret="sk_xxx",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
response = client.upload_file("./photo.png", name="marketing-hero", transform=True)
|
|
38
|
+
print(response)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
- `upload_file(path, name=None, transform=None)`
|
|
44
|
+
- `upload_files(paths, name=None, transform=None)`
|
|
45
|
+
- `list_files()`
|
|
46
|
+
- `get_file_metadata(file_id)`
|
|
47
|
+
- `update_file(file_id, path, name=None, transform=None)`
|
|
48
|
+
- `delete_file(file_id)`
|
|
49
|
+
- `get_metrics()`
|
|
50
|
+
- `build_file_url(file_id, **options)`
|
|
51
|
+
|
|
52
|
+
## Docs
|
|
53
|
+
|
|
54
|
+
https://vaultsens.com/
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# vaultsens-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK for VaultSens. API key + secret authentication with file upload and management helpers.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install vaultsens-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from vaultsens_sdk import VaultSensClient
|
|
15
|
+
|
|
16
|
+
client = VaultSensClient(
|
|
17
|
+
base_url="https://api.vaultsens.com",
|
|
18
|
+
api_key="fs_xxx",
|
|
19
|
+
api_secret="sk_xxx",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
response = client.upload_file("./photo.png", name="marketing-hero", transform=True)
|
|
23
|
+
print(response)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## API
|
|
27
|
+
|
|
28
|
+
- `upload_file(path, name=None, transform=None)`
|
|
29
|
+
- `upload_files(paths, name=None, transform=None)`
|
|
30
|
+
- `list_files()`
|
|
31
|
+
- `get_file_metadata(file_id)`
|
|
32
|
+
- `update_file(file_id, path, name=None, transform=None)`
|
|
33
|
+
- `delete_file(file_id)`
|
|
34
|
+
- `get_metrics()`
|
|
35
|
+
- `build_file_url(file_id, **options)`
|
|
36
|
+
|
|
37
|
+
## Docs
|
|
38
|
+
|
|
39
|
+
https://vaultsens.com/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vaultsens-sdk"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "VaultSens SDK for API key uploads and file management"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "VaultSens" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["vaultsens", "sdk", "storage", "upload"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Operating System :: OS Independent"
|
|
19
|
+
]
|
|
20
|
+
dependencies = ["requests>=2.31"]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://vaultsens.com/"
|
|
24
|
+
Repository = "https://github.com/vaultsens/vaultsens-sdk-python"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
include = ["vaultsens_sdk*"]
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _resolve_error_code(status: int, message: str) -> str:
|
|
10
|
+
m = message.lower()
|
|
11
|
+
if status == 413 and "storage limit" in m:
|
|
12
|
+
return "STORAGE_LIMIT"
|
|
13
|
+
if status == 413:
|
|
14
|
+
return "FILE_TOO_LARGE"
|
|
15
|
+
if status == 415:
|
|
16
|
+
return "MIME_TYPE_NOT_ALLOWED"
|
|
17
|
+
if status == 402:
|
|
18
|
+
return "SUBSCRIPTION_INACTIVE"
|
|
19
|
+
if status == 403 and "compression" in m:
|
|
20
|
+
return "COMPRESSION_NOT_ALLOWED"
|
|
21
|
+
if status == 403 and "folder" in m:
|
|
22
|
+
return "FOLDER_COUNT_LIMIT"
|
|
23
|
+
if status == 403 and ("file" in m or "maximum" in m):
|
|
24
|
+
return "FILE_COUNT_LIMIT"
|
|
25
|
+
if status == 403 and "email" in m:
|
|
26
|
+
return "EMAIL_NOT_VERIFIED"
|
|
27
|
+
if status == 400 and "already registered" in m:
|
|
28
|
+
return "EMAIL_ALREADY_REGISTERED"
|
|
29
|
+
if status == 400 and ("invalid email or password" in m or "invalid credentials" in m):
|
|
30
|
+
return "INVALID_CREDENTIALS"
|
|
31
|
+
if status == 400 and "otp" in m:
|
|
32
|
+
return "INVALID_OTP"
|
|
33
|
+
if status == 401:
|
|
34
|
+
return "UNAUTHORIZED"
|
|
35
|
+
if status == 404:
|
|
36
|
+
return "NOT_FOUND"
|
|
37
|
+
return "UNKNOWN"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class VaultSensError(Exception):
|
|
42
|
+
"""
|
|
43
|
+
Raised when the VaultSens API returns an error response.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
message: Human-readable error description from the API.
|
|
47
|
+
status: HTTP status code.
|
|
48
|
+
code: Machine-readable error code (e.g. ``"FILE_TOO_LARGE"``).
|
|
49
|
+
data: Raw response payload, if any.
|
|
50
|
+
|
|
51
|
+
Error codes:
|
|
52
|
+
FILE_TOO_LARGE – 413: file exceeds plan's maxFileSizeBytes
|
|
53
|
+
STORAGE_LIMIT – 413: total storage quota exceeded
|
|
54
|
+
FILE_COUNT_LIMIT – 403: plan's maxFilesCount reached
|
|
55
|
+
MIME_TYPE_NOT_ALLOWED – 415: file type blocked by plan
|
|
56
|
+
COMPRESSION_NOT_ALLOWED – 403: compression level not permitted by plan
|
|
57
|
+
SUBSCRIPTION_INACTIVE – 402: user subscription is not active
|
|
58
|
+
FOLDER_COUNT_LIMIT – 403: plan's maxFoldersCount reached
|
|
59
|
+
EMAIL_ALREADY_REGISTERED – 400: duplicate email on register
|
|
60
|
+
EMAIL_NOT_VERIFIED – 403: login before verifying email
|
|
61
|
+
INVALID_CREDENTIALS – 400: wrong email or password
|
|
62
|
+
INVALID_OTP – 400: bad/expired verification code
|
|
63
|
+
UNAUTHORIZED – 401
|
|
64
|
+
NOT_FOUND – 404
|
|
65
|
+
UNKNOWN – anything else
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
message: str
|
|
69
|
+
status: int
|
|
70
|
+
data: Optional[Any] = None
|
|
71
|
+
code: str = field(init=False)
|
|
72
|
+
|
|
73
|
+
def __post_init__(self) -> None:
|
|
74
|
+
self.code = _resolve_error_code(self.status, self.message)
|
|
75
|
+
|
|
76
|
+
def __str__(self) -> str:
|
|
77
|
+
return f"{self.status} [{self.code}]: {self.message}"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class VaultSensClient:
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
base_url: str,
|
|
84
|
+
api_key: Optional[str] = None,
|
|
85
|
+
api_secret: Optional[str] = None,
|
|
86
|
+
timeout: int = 30,
|
|
87
|
+
) -> None:
|
|
88
|
+
self.base_url = base_url.rstrip("/")
|
|
89
|
+
self.api_key = api_key
|
|
90
|
+
self.api_secret = api_secret
|
|
91
|
+
self.timeout = timeout
|
|
92
|
+
|
|
93
|
+
def set_auth(self, api_key: str, api_secret: str) -> None:
|
|
94
|
+
self.api_key = api_key
|
|
95
|
+
self.api_secret = api_secret
|
|
96
|
+
|
|
97
|
+
def _headers(self) -> Dict[str, str]:
|
|
98
|
+
if not self.api_key or not self.api_secret:
|
|
99
|
+
raise VaultSensError("API key and secret are required", 401)
|
|
100
|
+
return {
|
|
101
|
+
"x-api-key": self.api_key,
|
|
102
|
+
"x-api-secret": self.api_secret,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def _request(self, method: str, path: str, **kwargs: Any) -> Any:
|
|
106
|
+
url = f"{self.base_url}{path}"
|
|
107
|
+
response = requests.request(method, url, headers=self._headers(), timeout=self.timeout, **kwargs)
|
|
108
|
+
try:
|
|
109
|
+
payload = response.json()
|
|
110
|
+
except ValueError:
|
|
111
|
+
payload = response.text
|
|
112
|
+
|
|
113
|
+
if not response.ok:
|
|
114
|
+
message = payload.get("message") if isinstance(payload, dict) else response.reason
|
|
115
|
+
raise VaultSensError(message or response.reason, response.status_code, payload)
|
|
116
|
+
|
|
117
|
+
return payload
|
|
118
|
+
|
|
119
|
+
def upload_file(self, file_path: str, name: Optional[str] = None, compression: Optional[str] = None, folder_id: Optional[str] = None) -> Any:
|
|
120
|
+
files = {"file": open(file_path, "rb")}
|
|
121
|
+
data: Dict[str, Any] = {}
|
|
122
|
+
if name:
|
|
123
|
+
data["name"] = name
|
|
124
|
+
if compression is not None:
|
|
125
|
+
data["compression"] = compression
|
|
126
|
+
if folder_id is not None:
|
|
127
|
+
data["folderId"] = folder_id
|
|
128
|
+
try:
|
|
129
|
+
return self._request("POST", "/api/v1/files/upload", files=files, data=data)
|
|
130
|
+
finally:
|
|
131
|
+
files["file"].close()
|
|
132
|
+
|
|
133
|
+
def upload_files(self, file_paths: list[str], name: Optional[str] = None, compression: Optional[str] = None, folder_id: Optional[str] = None) -> Any:
|
|
134
|
+
files = [("files", open(path, "rb")) for path in file_paths]
|
|
135
|
+
data: Dict[str, Any] = {}
|
|
136
|
+
if name:
|
|
137
|
+
data["name"] = name
|
|
138
|
+
if compression is not None:
|
|
139
|
+
data["compression"] = compression
|
|
140
|
+
if folder_id is not None:
|
|
141
|
+
data["folderId"] = folder_id
|
|
142
|
+
try:
|
|
143
|
+
return self._request("POST", "/api/v1/files/upload", files=files, data=data)
|
|
144
|
+
finally:
|
|
145
|
+
for _, fh in files:
|
|
146
|
+
fh.close()
|
|
147
|
+
|
|
148
|
+
def list_files(self, folder_id: Optional[str] = None) -> Any:
|
|
149
|
+
path = f"/api/v1/files?folderId={folder_id}" if folder_id else "/api/v1/files"
|
|
150
|
+
return self._request("GET", path)
|
|
151
|
+
|
|
152
|
+
def list_folders(self) -> Any:
|
|
153
|
+
return self._request("GET", "/api/v1/folders")
|
|
154
|
+
|
|
155
|
+
def create_folder(self, name: str, parent_id: Optional[str] = None) -> Any:
|
|
156
|
+
data: Dict[str, Any] = {"name": name}
|
|
157
|
+
if parent_id is not None:
|
|
158
|
+
data["parentId"] = parent_id
|
|
159
|
+
return self._request("POST", "/api/v1/folders", json=data)
|
|
160
|
+
|
|
161
|
+
def rename_folder(self, folder_id: str, name: str) -> Any:
|
|
162
|
+
return self._request("PATCH", f"/api/v1/folders/{folder_id}", json={"name": name})
|
|
163
|
+
|
|
164
|
+
def delete_folder(self, folder_id: str) -> Any:
|
|
165
|
+
return self._request("DELETE", f"/api/v1/folders/{folder_id}")
|
|
166
|
+
|
|
167
|
+
def get_file_metadata(self, file_id: str) -> Any:
|
|
168
|
+
return self._request("GET", f"/api/v1/files/metadata/{file_id}")
|
|
169
|
+
|
|
170
|
+
def update_file(
|
|
171
|
+
self,
|
|
172
|
+
file_id: str,
|
|
173
|
+
file_path: str,
|
|
174
|
+
name: Optional[str] = None,
|
|
175
|
+
compression: Optional[str] = None,
|
|
176
|
+
) -> Any:
|
|
177
|
+
files = {"file": open(file_path, "rb")}
|
|
178
|
+
data: Dict[str, Any] = {}
|
|
179
|
+
if name:
|
|
180
|
+
data["name"] = name
|
|
181
|
+
if compression is not None:
|
|
182
|
+
data["compression"] = compression
|
|
183
|
+
try:
|
|
184
|
+
return self._request("PUT", f"/api/v1/files/{file_id}", files=files, data=data)
|
|
185
|
+
finally:
|
|
186
|
+
files["file"].close()
|
|
187
|
+
|
|
188
|
+
def delete_file(self, file_id: str) -> Any:
|
|
189
|
+
return self._request("DELETE", f"/api/v1/files/{file_id}")
|
|
190
|
+
|
|
191
|
+
def get_metrics(self) -> Any:
|
|
192
|
+
return self._request("GET", "/api/v1/metrics")
|
|
193
|
+
|
|
194
|
+
def build_file_url(self, file_id: str, **options: Any) -> str:
|
|
195
|
+
url = f"{self.base_url}/api/v1/files/{file_id}"
|
|
196
|
+
if options:
|
|
197
|
+
query = "&".join(f"{k}={v}" for k, v in options.items())
|
|
198
|
+
return f"{url}?{query}"
|
|
199
|
+
return url
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vaultsens-sdk
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: VaultSens SDK for API key uploads and file management
|
|
5
|
+
Author: VaultSens
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://vaultsens.com/
|
|
8
|
+
Project-URL: Repository, https://github.com/vaultsens/vaultsens-sdk-python
|
|
9
|
+
Keywords: vaultsens,sdk,storage,upload
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: requests>=2.31
|
|
15
|
+
|
|
16
|
+
# vaultsens-sdk
|
|
17
|
+
|
|
18
|
+
Python SDK for VaultSens. API key + secret authentication with file upload and management helpers.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install vaultsens-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from vaultsens_sdk import VaultSensClient
|
|
30
|
+
|
|
31
|
+
client = VaultSensClient(
|
|
32
|
+
base_url="https://api.vaultsens.com",
|
|
33
|
+
api_key="fs_xxx",
|
|
34
|
+
api_secret="sk_xxx",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
response = client.upload_file("./photo.png", name="marketing-hero", transform=True)
|
|
38
|
+
print(response)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
- `upload_file(path, name=None, transform=None)`
|
|
44
|
+
- `upload_files(paths, name=None, transform=None)`
|
|
45
|
+
- `list_files()`
|
|
46
|
+
- `get_file_metadata(file_id)`
|
|
47
|
+
- `update_file(file_id, path, name=None, transform=None)`
|
|
48
|
+
- `delete_file(file_id)`
|
|
49
|
+
- `get_metrics()`
|
|
50
|
+
- `build_file_url(file_id, **options)`
|
|
51
|
+
|
|
52
|
+
## Docs
|
|
53
|
+
|
|
54
|
+
https://vaultsens.com/
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
vaultsens_sdk/__init__.py
|
|
4
|
+
vaultsens_sdk/client.py
|
|
5
|
+
vaultsens_sdk.egg-info/PKG-INFO
|
|
6
|
+
vaultsens_sdk.egg-info/SOURCES.txt
|
|
7
|
+
vaultsens_sdk.egg-info/dependency_links.txt
|
|
8
|
+
vaultsens_sdk.egg-info/requires.txt
|
|
9
|
+
vaultsens_sdk.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.31
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vaultsens_sdk
|