hyze-cloud 0.1.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.
- hyze_cloud-0.1.0.dist-info/METADATA +263 -0
- hyze_cloud-0.1.0.dist-info/RECORD +17 -0
- hyze_cloud-0.1.0.dist-info/WHEEL +4 -0
- hyze_cloud-0.1.0.dist-info/licenses/LICENSE +21 -0
- hyzecloud/__init__.py +143 -0
- hyzecloud/_url.py +26 -0
- hyzecloud/client.py +409 -0
- hyzecloud/errors.py +118 -0
- hyzecloud/py.typed +0 -0
- hyzecloud/resources/__init__.py +24 -0
- hyzecloud/resources/api_keys.py +69 -0
- hyzecloud/resources/apps.py +252 -0
- hyzecloud/resources/databases.py +142 -0
- hyzecloud/resources/github.py +55 -0
- hyzecloud/resources/invoices.py +41 -0
- hyzecloud/resources/plans.py +28 -0
- hyzecloud/types.py +448 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: hyze-cloud
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Hyze Cloud API
|
|
5
|
+
Project-URL: Homepage, https://hyzecloud.com
|
|
6
|
+
Project-URL: Documentation, https://docs.hyzecloud.app
|
|
7
|
+
Project-URL: Repository, https://github.com/Hyze-Cloud/hyzecloud-sdk-python
|
|
8
|
+
Project-URL: Issues, https://github.com/Hyze-Cloud/hyzecloud-sdk-python/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/Hyze-Cloud/hyzecloud-sdk-python/releases
|
|
10
|
+
Author: Hyze Cloud
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api,deploy,hyze,hyzecloud,paas,python,sdk
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx<1,>=0.27
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# hyze-cloud
|
|
33
|
+
|
|
34
|
+
[](https://github.com/Hyze-Cloud/hyzecloud-sdk-python/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/hyze-cloud/)
|
|
36
|
+
[](https://pypi.org/project/hyze-cloud/)
|
|
37
|
+
[](./LICENSE)
|
|
38
|
+
|
|
39
|
+
Official **Python** SDK for the [Hyze Cloud API](https://docs.hyzecloud.app).
|
|
40
|
+
|
|
41
|
+
- **Sync and async** clients with the same surface — `client.apps.list()` or `await`
|
|
42
|
+
- Typed helpers for apps, databases, API keys, invoices, GitHub and plans
|
|
43
|
+
- One dependency (`httpx`), and it is the only one
|
|
44
|
+
- Consistent `HyzeError` carrying status, code and `Retry-After`
|
|
45
|
+
- Ships `py.typed`, so editors and type checkers see the shapes
|
|
46
|
+
|
|
47
|
+
This is a port of the TypeScript SDK ([`@hyze-cloud/sdk`](https://github.com/Hyze-Cloud/hyzecloud-sdk-ts)):
|
|
48
|
+
same resources, same routes, same error shape. The one naming difference is deliberate — Python
|
|
49
|
+
callers use `snake_case` (`memory_mb`) and the SDK translates it to the API's `camelCase`
|
|
50
|
+
(`memoryMB`).
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install hyze-cloud
|
|
56
|
+
# or
|
|
57
|
+
uv add hyze-cloud
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires **Python 3.10+**.
|
|
61
|
+
|
|
62
|
+
## Quickstart
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from hyzecloud import HyzeCloud, HyzeError
|
|
66
|
+
|
|
67
|
+
client = HyzeCloud(
|
|
68
|
+
# api_key="hyze_...", # defaults to $HYZE_API_KEY
|
|
69
|
+
# base_url="https://api.hyzecloud.com/api", # the default
|
|
70
|
+
# workspace_id="org_...", # optional scope
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
for app in client.apps.list()["apps"]:
|
|
74
|
+
print(app["name"], app["status"])
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
client.apps.restart("app_001")
|
|
78
|
+
except HyzeError as err:
|
|
79
|
+
print(err.status, err.code, err.message)
|
|
80
|
+
if err.is_rate_limited:
|
|
81
|
+
print("retry after", err.retry_after_seconds)
|
|
82
|
+
raise
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Close the client when you are done, or use it as a context manager:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
with HyzeCloud() as client:
|
|
89
|
+
client.plans.current()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Async
|
|
93
|
+
|
|
94
|
+
The same calls, awaited. `AsyncHyzeCloud` is the client to reach for inside FastAPI, aiohttp or
|
|
95
|
+
any asyncio program:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import asyncio
|
|
99
|
+
from hyzecloud import AsyncHyzeCloud
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
async def main() -> None:
|
|
103
|
+
async with AsyncHyzeCloud() as client:
|
|
104
|
+
apps = await client.apps.list()
|
|
105
|
+
print(len(apps["apps"]))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
asyncio.run(main())
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Apps
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
# List / get
|
|
115
|
+
apps = client.apps.list()["apps"]
|
|
116
|
+
detail = client.apps.get("app_001")["container"]
|
|
117
|
+
|
|
118
|
+
# Lifecycle
|
|
119
|
+
client.apps.start("app_001")
|
|
120
|
+
client.apps.stop("app_001")
|
|
121
|
+
client.apps.restart("app_001")
|
|
122
|
+
|
|
123
|
+
# Logs, env, deploy history
|
|
124
|
+
client.apps.logs("app_001", tail=200, timestamps=True)
|
|
125
|
+
client.apps.get_env("app_001")
|
|
126
|
+
client.apps.set_env("app_001", {"NODE_ENV": "production"})
|
|
127
|
+
client.apps.deployments("app_001", limit=30)
|
|
128
|
+
|
|
129
|
+
# Deploy from a ZIP — a path, raw bytes, or an open file all work.
|
|
130
|
+
# A path is read into memory; pass an open file for a large archive (it gets streamed).
|
|
131
|
+
client.apps.deploy_from_zip(
|
|
132
|
+
file="./app.zip",
|
|
133
|
+
name="my-api",
|
|
134
|
+
runtime="python",
|
|
135
|
+
memory_mb=512,
|
|
136
|
+
expose_port=8000,
|
|
137
|
+
subdomain="my-api",
|
|
138
|
+
# startup_command omitted (or "auto") -> Hyze detects the start command
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Detect the env vars of a ZIP without deploying it
|
|
142
|
+
client.apps.inspect_env("./app.zip")
|
|
143
|
+
|
|
144
|
+
# Deploy from a connected GitHub repository
|
|
145
|
+
client.apps.deploy_from_repo(
|
|
146
|
+
name="my-api",
|
|
147
|
+
runtime="python",
|
|
148
|
+
memory_mb=512,
|
|
149
|
+
repository={"id": 123, "owner": "acme", "name": "api", "branch": "main"},
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Backups
|
|
153
|
+
client.apps.create_backup("app_001")
|
|
154
|
+
client.apps.list_backups("app_001")
|
|
155
|
+
client.apps.restore_backup("app_001", "backup_001")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Databases
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
client.databases.create(name="prod-postgres", engine="postgresql", memory_mb=1024, storage_gb=20)
|
|
162
|
+
client.databases.list()
|
|
163
|
+
client.databases.stats("db_001")
|
|
164
|
+
client.databases.rotate_password("db_001")
|
|
165
|
+
client.databases.create_backup("db_001")
|
|
166
|
+
client.databases.restore("db_001", "backup_001")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## API keys, invoices, GitHub, plans
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
keys = client.api_keys.list()["keys"]
|
|
173
|
+
created = client.api_keys.create(name="ci")
|
|
174
|
+
# created["key"]["key"] is the one-time secret — it is never returned again
|
|
175
|
+
|
|
176
|
+
invoices = client.invoices.list()["invoices"]
|
|
177
|
+
pix = client.invoices.create_pix(plan_id="pro", interval="month")
|
|
178
|
+
# pix["invoice"]["brCode"] / ["brCodeBase64"] for the checkout screen
|
|
179
|
+
client.invoices.status(pix["invoice"]["id"], include_pix=True)
|
|
180
|
+
|
|
181
|
+
client.github.status()
|
|
182
|
+
client.github.repos()
|
|
183
|
+
client.github.branches("acme", "api")
|
|
184
|
+
client.github.detect_runtime("acme", "api", branch="main")
|
|
185
|
+
|
|
186
|
+
current = client.plans.current() # plan + usage, no nested apps/databases lists
|
|
187
|
+
client.plans.list()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Error handling
|
|
191
|
+
|
|
192
|
+
Every failure raises `HyzeError`, including a 2xx response whose body is shaped like an error.
|
|
193
|
+
|
|
194
|
+
| Attribute | Meaning |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `status` | HTTP status (401 when a 2xx body looked like an error) |
|
|
197
|
+
| `code` | Structured code from the payload, when the API sent one |
|
|
198
|
+
| `message` | Human-readable message |
|
|
199
|
+
| `body` | The decoded payload, untouched |
|
|
200
|
+
| `retry_after_seconds` | From the `Retry-After` header, when present |
|
|
201
|
+
|
|
202
|
+
`is_rate_limited` (`429`), `is_unauthorized` (`401`/`403`) and `is_not_found` (`404`) are there so
|
|
203
|
+
callers do not have to compare numbers by hand.
|
|
204
|
+
|
|
205
|
+
## Low-level access
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
client.get("/apps/")
|
|
209
|
+
client.post("/apps/app_001/restart")
|
|
210
|
+
client.request("GET", "/apps/", query={"workspaceId": "org_1"})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Environment
|
|
214
|
+
|
|
215
|
+
| Variable | Description |
|
|
216
|
+
| --- | --- |
|
|
217
|
+
| `HYZE_API_KEY` | Default API key when `api_key` is omitted |
|
|
218
|
+
| `HYZE_API_URL` | Override the base URL (default `https://api.hyzecloud.com/api`) |
|
|
219
|
+
|
|
220
|
+
## Development
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
uv venv && uv pip install -e ".[dev]"
|
|
224
|
+
.venv/bin/python -m pytest
|
|
225
|
+
.venv/bin/python -m mypy
|
|
226
|
+
.venv/bin/python -m ruff check .
|
|
227
|
+
.venv/bin/python scripts/check_api_routes.py # are the routes this SDK calls still there?
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`check_api_routes.py` hits the production API **unauthenticated**: a 404 means the route is gone,
|
|
231
|
+
any other status (401/400/…) means it exists. It runs on every PR and before publishing — a
|
|
232
|
+
published client calling a dead route is a 404 for the user.
|
|
233
|
+
|
|
234
|
+
### Live smoke test
|
|
235
|
+
|
|
236
|
+
Exercises the read paths against the real API with your key:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
HYZE_API_KEY=hyze_xxx .venv/bin/python scripts/live_smoke.py
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Release
|
|
243
|
+
|
|
244
|
+
The tag drives the version: `vX.Y.Z` must match `pyproject.toml`, otherwise the workflow aborts
|
|
245
|
+
before publishing.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# bump the version, then
|
|
249
|
+
git tag v0.1.1 && git push origin v0.1.1
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`release.yml` runs ruff + mypy + pytest + `check_api_routes.py`, builds the sdist and the wheel,
|
|
253
|
+
and publishes to PyPI through **Trusted Publishing** (OIDC) — there is no API token stored anywhere.
|
|
254
|
+
|
|
255
|
+
## Docs
|
|
256
|
+
|
|
257
|
+
- [Hyze Cloud Docs](https://docs.hyzecloud.app)
|
|
258
|
+
- [API introduction](https://docs.hyzecloud.app/api-reference/introduction)
|
|
259
|
+
- [Rate limits](https://docs.hyzecloud.app/en/concepts/rate-limits)
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
hyzecloud/__init__.py,sha256=IYhNXJc_qk9Eul_E5AM7U7je_p-hlpTIR5thKfEnuW0,3465
|
|
2
|
+
hyzecloud/_url.py,sha256=kRXIvKbHDHAiHk8aWXHe0Bw-U_oPBxn6cbrxjdR-5Fs,828
|
|
3
|
+
hyzecloud/client.py,sha256=-DAFoJe-UzHaVbDPr9_smx-b2W8FbikIc4a0TBJgspc,13936
|
|
4
|
+
hyzecloud/errors.py,sha256=QKZIqDMeGZfuWi5oGO-ll343Bvd5Fb2v1LchM53llCM,3466
|
|
5
|
+
hyzecloud/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
hyzecloud/types.py,sha256=kNKV7QJkrtQJnTPpThk-6Tinq8j86g7wKVACQi-hdCk,10437
|
|
7
|
+
hyzecloud/resources/__init__.py,sha256=-2gJMZE_oxaoLSu3u9vBWlkhJgv_aqjg_k2QAHPC0xw,665
|
|
8
|
+
hyzecloud/resources/api_keys.py,sha256=ef_vOIT4SoAkjUaB1mXl88NaK8QiCqp25Hiaz0EiN38,2095
|
|
9
|
+
hyzecloud/resources/apps.py,sha256=TBj0bgXYiTscoEVrAQ5BepOFP8JuGwhVwZxzXjl2Ih0,9096
|
|
10
|
+
hyzecloud/resources/databases.py,sha256=51cA6ImkIjFX8s7pVXs_X1EQJc1HGAVtskPJmYNZyBI,5203
|
|
11
|
+
hyzecloud/resources/github.py,sha256=5TvHRvNQFYN_if5AJVxRMUg9OCn-bOtABbgJnWyp598,1832
|
|
12
|
+
hyzecloud/resources/invoices.py,sha256=uYnAyIHNyXVFBrykcVlD9qfJ1-OK6iVjnG8ht2CRsho,1349
|
|
13
|
+
hyzecloud/resources/plans.py,sha256=3DI0_9RGC6QycIdPadWoD9Im2bksYW4SiXyaYOLNcD8,713
|
|
14
|
+
hyze_cloud-0.1.0.dist-info/METADATA,sha256=AQ_ZHnWJ3rRa4Myx9pHC2tXO4MSIofTXIZDPqwyZH3k,8229
|
|
15
|
+
hyze_cloud-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
16
|
+
hyze_cloud-0.1.0.dist-info/licenses/LICENSE,sha256=A0cg9rg53IWNTe-qsGjEexNWxA-SY3z0kjUXyRISdS0,1067
|
|
17
|
+
hyze_cloud-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hyze Cloud
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
hyzecloud/__init__.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Official Python SDK for the Hyze Cloud API.
|
|
2
|
+
|
|
3
|
+
from hyzecloud import HyzeCloud
|
|
4
|
+
|
|
5
|
+
client = HyzeCloud(api_key="hyze_...")
|
|
6
|
+
for app in client.apps.list()["apps"]:
|
|
7
|
+
print(app["name"], app["status"])
|
|
8
|
+
|
|
9
|
+
An async client with the same surface is available as :class:`AsyncHyzeCloud`:
|
|
10
|
+
|
|
11
|
+
from hyzecloud import AsyncHyzeCloud
|
|
12
|
+
|
|
13
|
+
async with AsyncHyzeCloud() as client: # reads HYZE_API_KEY
|
|
14
|
+
apps = await client.apps.list()
|
|
15
|
+
|
|
16
|
+
This mirrors the TypeScript SDK (``@hyze-cloud/sdk``): same resources, same routes, same
|
|
17
|
+
error shape.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from importlib.metadata import PackageNotFoundError
|
|
23
|
+
from importlib.metadata import version as _version
|
|
24
|
+
|
|
25
|
+
from .client import DEFAULT_BASE_URL, DEFAULT_TIMEOUT, AsyncHyzeCloud, HyzeCloud, create_hyze_client
|
|
26
|
+
from .errors import HyzeError, looks_like_error_payload, parse_error_body
|
|
27
|
+
from .resources import (
|
|
28
|
+
ApiKeysResource,
|
|
29
|
+
AppsResource,
|
|
30
|
+
DatabasesResource,
|
|
31
|
+
GithubResource,
|
|
32
|
+
InvoicesResource,
|
|
33
|
+
PlansResource,
|
|
34
|
+
)
|
|
35
|
+
from .types import (
|
|
36
|
+
ApiKeyCreated,
|
|
37
|
+
ApiKeyCreateResponse,
|
|
38
|
+
ApiKeyItem,
|
|
39
|
+
ApiKeysListResponse,
|
|
40
|
+
ApiKeyUpdateResponse,
|
|
41
|
+
AppDeployment,
|
|
42
|
+
AppDeploymentsResponse,
|
|
43
|
+
AppDeploymentStatus,
|
|
44
|
+
AppDetail,
|
|
45
|
+
AppDetailResponse,
|
|
46
|
+
AppEnvResponse,
|
|
47
|
+
AppListItem,
|
|
48
|
+
AppLogsResponse,
|
|
49
|
+
AppsListResponse,
|
|
50
|
+
BillingInterval,
|
|
51
|
+
ContainerStats,
|
|
52
|
+
CreateApiKeyInput,
|
|
53
|
+
CreateDatabaseInput,
|
|
54
|
+
CreatePixInvoiceInput,
|
|
55
|
+
CurrentPlanResponse,
|
|
56
|
+
DatabaseEngine,
|
|
57
|
+
DatabaseItem,
|
|
58
|
+
DatabaseResponse,
|
|
59
|
+
DatabasesListResponse,
|
|
60
|
+
DeployFromRepoInput,
|
|
61
|
+
DeployFromZipInput,
|
|
62
|
+
DeployRepository,
|
|
63
|
+
GithubStatusResponse,
|
|
64
|
+
InvoiceBilling,
|
|
65
|
+
InvoiceDetail,
|
|
66
|
+
InvoiceDetailResponse,
|
|
67
|
+
InvoiceListItem,
|
|
68
|
+
InvoicePlanSummary,
|
|
69
|
+
InvoicesListResponse,
|
|
70
|
+
PlanInfo,
|
|
71
|
+
PlanPriceInfo,
|
|
72
|
+
PlansListResponse,
|
|
73
|
+
PlanUsage,
|
|
74
|
+
RequestOptions,
|
|
75
|
+
Runtime,
|
|
76
|
+
UpdateApiKeyInput,
|
|
77
|
+
UpdateAppSettingsInput,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
__version__ = _version("hyze-cloud")
|
|
82
|
+
except PackageNotFoundError: # running from a source tree without an install
|
|
83
|
+
__version__ = "0.0.0"
|
|
84
|
+
|
|
85
|
+
__all__ = [
|
|
86
|
+
"DEFAULT_BASE_URL",
|
|
87
|
+
"DEFAULT_TIMEOUT",
|
|
88
|
+
"ApiKeyCreateResponse",
|
|
89
|
+
"ApiKeyCreated",
|
|
90
|
+
"ApiKeyItem",
|
|
91
|
+
"ApiKeyUpdateResponse",
|
|
92
|
+
"ApiKeysListResponse",
|
|
93
|
+
"ApiKeysResource",
|
|
94
|
+
"AppDeployment",
|
|
95
|
+
"AppDeploymentStatus",
|
|
96
|
+
"AppDeploymentsResponse",
|
|
97
|
+
"AppDetail",
|
|
98
|
+
"AppDetailResponse",
|
|
99
|
+
"AppEnvResponse",
|
|
100
|
+
"AppListItem",
|
|
101
|
+
"AppLogsResponse",
|
|
102
|
+
"AppsListResponse",
|
|
103
|
+
"AppsResource",
|
|
104
|
+
"AsyncHyzeCloud",
|
|
105
|
+
"BillingInterval",
|
|
106
|
+
"ContainerStats",
|
|
107
|
+
"CreateApiKeyInput",
|
|
108
|
+
"CreateDatabaseInput",
|
|
109
|
+
"CreatePixInvoiceInput",
|
|
110
|
+
"CurrentPlanResponse",
|
|
111
|
+
"DatabaseEngine",
|
|
112
|
+
"DatabaseItem",
|
|
113
|
+
"DatabaseResponse",
|
|
114
|
+
"DatabasesListResponse",
|
|
115
|
+
"DatabasesResource",
|
|
116
|
+
"DeployFromRepoInput",
|
|
117
|
+
"DeployFromZipInput",
|
|
118
|
+
"DeployRepository",
|
|
119
|
+
"GithubResource",
|
|
120
|
+
"GithubStatusResponse",
|
|
121
|
+
"HyzeCloud",
|
|
122
|
+
"HyzeError",
|
|
123
|
+
"InvoiceBilling",
|
|
124
|
+
"InvoiceDetail",
|
|
125
|
+
"InvoiceDetailResponse",
|
|
126
|
+
"InvoiceListItem",
|
|
127
|
+
"InvoicePlanSummary",
|
|
128
|
+
"InvoicesListResponse",
|
|
129
|
+
"InvoicesResource",
|
|
130
|
+
"PlanInfo",
|
|
131
|
+
"PlanPriceInfo",
|
|
132
|
+
"PlanUsage",
|
|
133
|
+
"PlansListResponse",
|
|
134
|
+
"PlansResource",
|
|
135
|
+
"RequestOptions",
|
|
136
|
+
"Runtime",
|
|
137
|
+
"UpdateApiKeyInput",
|
|
138
|
+
"UpdateAppSettingsInput",
|
|
139
|
+
"__version__",
|
|
140
|
+
"create_hyze_client",
|
|
141
|
+
"looks_like_error_payload",
|
|
142
|
+
"parse_error_body",
|
|
143
|
+
]
|
hyzecloud/_url.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""URL helpers shared by the client and the resources.
|
|
2
|
+
|
|
3
|
+
Kept in its own module so resources can import it without importing the client, which
|
|
4
|
+
would be a cycle (the client imports every resource).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from urllib.parse import quote
|
|
10
|
+
|
|
11
|
+
__all__ = ["join_url", "segment"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def join_url(base: str, path: str) -> str:
|
|
15
|
+
"""Append a path to a base URL without doubling or dropping the slash."""
|
|
16
|
+
normalized_path = path if path.startswith("/") else f"/{path}"
|
|
17
|
+
return f"{base.rstrip('/')}{normalized_path}"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def segment(value: object) -> str:
|
|
21
|
+
"""Percent-encode one path segment.
|
|
22
|
+
|
|
23
|
+
The TypeScript SDK wraps every id in ``encodeURIComponent``. Without this, an id
|
|
24
|
+
containing a space, a slash or a ``?`` would silently change the route.
|
|
25
|
+
"""
|
|
26
|
+
return quote(str(value), safe="")
|