computenexa 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.
- computenexa-0.1.1/.github/workflows/publish.yml +21 -0
- computenexa-0.1.1/.github/workflows/test.yml +17 -0
- computenexa-0.1.1/.gitignore +7 -0
- computenexa-0.1.1/CHANGELOG.md +11 -0
- computenexa-0.1.1/LICENSE +21 -0
- computenexa-0.1.1/PKG-INFO +155 -0
- computenexa-0.1.1/README.md +132 -0
- computenexa-0.1.1/pyproject.toml +44 -0
- computenexa-0.1.1/src/computenexa/__init__.py +60 -0
- computenexa-0.1.1/src/computenexa/client.py +235 -0
- computenexa-0.1.1/src/computenexa/errors.py +102 -0
- computenexa-0.1.1/src/computenexa/models.py +261 -0
- computenexa-0.1.1/src/computenexa/py.typed +0 -0
- computenexa-0.1.1/tests/test_client.py +217 -0
- computenexa-0.1.1/tests/test_integration.py +48 -0
- computenexa-0.1.1/uv.lock +356 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Publishes to PyPI when a GitHub release is published (tag v<version>, matching pyproject.toml).
|
|
2
|
+
# Uses PyPI trusted publishing: no password or token is stored anywhere. One-time setup on pypi.org
|
|
3
|
+
# (account support@computenexa.com): add a trusted publisher for this repo, workflow publish.yml, environment pypi.
|
|
4
|
+
name: publish
|
|
5
|
+
on:
|
|
6
|
+
release:
|
|
7
|
+
types: [published]
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: pypi
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: astral-sh/setup-uv@v5
|
|
17
|
+
- name: The tag matches the package version
|
|
18
|
+
run: test "${GITHUB_REF_NAME#v}" = "$(grep -m1 '^version' pyproject.toml | cut -d'"' -f2)"
|
|
19
|
+
- run: uv sync && uv run pytest -q
|
|
20
|
+
- run: uv build
|
|
21
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
jobs:
|
|
7
|
+
test:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: astral-sh/setup-uv@v5
|
|
15
|
+
- run: uv sync --python ${{ matrix.python }}
|
|
16
|
+
- run: uv run ruff check src tests
|
|
17
|
+
- run: uv run pytest -q
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
First release on PyPI (0.1.0 was never uploaded: PyPI refused its support link). Same code as 0.1.0.
|
|
6
|
+
|
|
7
|
+
## 0.1.0
|
|
8
|
+
|
|
9
|
+
First release: account and balance, catalog (GPUs, apps, recommended models, image contents), launch / get / list /
|
|
10
|
+
extend / stop, `with client.gpu(...)` that always stops the GPU, projects, SSH keys, ledger; one exception per kind
|
|
11
|
+
of refusal; reads retried on 429 and 5xx, launches never sent twice.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ComputeNexa
|
|
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.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: computenexa
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python client for ComputeNexa: private GPUs for your business, launched and stopped from code.
|
|
5
|
+
Project-URL: Homepage, https://computenexa.com
|
|
6
|
+
Project-URL: Documentation, https://app.computenexa.com/help/api
|
|
7
|
+
Project-URL: API reference, https://app.computenexa.com/help/api/reference
|
|
8
|
+
Project-URL: Support, https://app.computenexa.com/help
|
|
9
|
+
Author-email: ComputeNexa <support@computenexa.com>
|
|
10
|
+
Maintainer-email: ComputeNexa <support@computenexa.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: ai,cloud,computenexa,gpu,inference,llm,private ai,training
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: httpx<1,>=0.27
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# ComputeNexa Python SDK
|
|
25
|
+
|
|
26
|
+
Launch, use and stop private GPUs on [ComputeNexa](https://computenexa.com) from Python. Each GPU is reserved for
|
|
27
|
+
your team, runs open AI models or your own code, and is paid by the minute from your team's prepaid credits.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install computenexa
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
Create an API key in the dashboard under **API keys** ("Launch and stop" to launch), then:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
export CNX_API_KEY="cnxk_..."
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from computenexa import Client
|
|
43
|
+
|
|
44
|
+
cnx = Client() # reads CNX_API_KEY
|
|
45
|
+
|
|
46
|
+
# Launch an RTX 4090 with JupyterLab and PyTorch for 2 hours; it's stopped when the block ends,
|
|
47
|
+
# even if your code fails, and unused minutes are refunded.
|
|
48
|
+
with cnx.gpu("rtx-4090", app="datascience", hours=2) as machine:
|
|
49
|
+
print(machine.ssh_command) # ssh cnx-7f3a9c@ssh.computenexa.com
|
|
50
|
+
... # your work
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Choose a GPU and an app
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
catalog = cnx.catalog() # live prices and stock; catalog.apps describes each app
|
|
57
|
+
for gpu in catalog.available(app="chat"): # for sale now, cheapest first
|
|
58
|
+
print(gpu.slug, gpu.vram_gb, "GB", gpu.price_per_hour_cents / 100, "$/h")
|
|
59
|
+
|
|
60
|
+
chat = catalog.apps["chat"]
|
|
61
|
+
print(chat.recommended_model(vram_gb=48)) # our model pick for a 48 GB GPU
|
|
62
|
+
print(cnx.image_contents("datascience")) # every package and version installed
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
| `app=` | On the launch page | For |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `chat` | Private Chat | chat with open AI models about your documents, in your browser |
|
|
68
|
+
| `imagegen` | Image Generation (ComfyUI) | images with SDXL or FLUX |
|
|
69
|
+
| `modelapi` | Model API (vLLM) | an AI model behind your own API key |
|
|
70
|
+
| `voice` | Voice Agent | speech in, spoken AI reply out |
|
|
71
|
+
| `datascience` | Notebook (Jupyter) | JupyterLab, PyTorch, pandas: analysis, training, fine-tuning |
|
|
72
|
+
| `basic` | Basic (SSH only) | Ubuntu + CUDA for your own code |
|
|
73
|
+
|
|
74
|
+
## Keep files between sessions with projects
|
|
75
|
+
|
|
76
|
+
A project is saved storage: launched with it, a GPU starts with the project's files in `~/work` and saves
|
|
77
|
+
`~/work` back automatically.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
project = cnx.get_or_create_project("titanic-training")
|
|
81
|
+
machine = cnx.launch("l40s", app="datascience", hours=4, project=project, label="nightly training")
|
|
82
|
+
machine.wait_until_running(on_progress=lambda m: print(m.state, m.startup_progress or ""))
|
|
83
|
+
print(machine.ssh_command)
|
|
84
|
+
# ... later
|
|
85
|
+
machine.stop()
|
|
86
|
+
print("refunded", machine.refunded_cents / 100)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Machines
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
cnx.list_instances(active=True) # your running and starting machines
|
|
93
|
+
cnx.list_instances(everyone=True) # the whole team's (owners and admins)
|
|
94
|
+
machine = cnx.get_instance("cnx-7f3a9c")
|
|
95
|
+
machine.extend(hours=1) # same price it launched with
|
|
96
|
+
machine.stop() # stops if running, cancels if still starting
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Account, credits and SSH keys
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
me = cnx.account()
|
|
103
|
+
print(me.email, me.organization.name, me.organization.role, me.balance, me.max_concurrent_gpus)
|
|
104
|
+
for entry in cnx.ledger(limit=20):
|
|
105
|
+
print(entry.created_at, entry.description, entry.amount_cents / 100)
|
|
106
|
+
|
|
107
|
+
cnx.add_ssh_key("Work laptop", open("/Users/me/.ssh/id_ed25519.pub").read()) # the PUBLIC key only
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Errors
|
|
111
|
+
|
|
112
|
+
Every refusal raises a subclass of `computenexa.ComputeNexaError` with a stable `code`, a `message` you can show
|
|
113
|
+
and a `request_id` to quote to support:
|
|
114
|
+
|
|
115
|
+
| Exception | When |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `InsufficientCreditsError` | not enough credits for the launch or extension |
|
|
118
|
+
| `NoCapacityError` | that GPU is fully booked right now: retry or pick another |
|
|
119
|
+
| `GpuLimitReachedError` | your team (or you) already run as many GPUs as allowed |
|
|
120
|
+
| `ProjectInUseError` | another GPU is using the project |
|
|
121
|
+
| `AuthenticationError` | the key is missing, mistyped or revoked |
|
|
122
|
+
| `PermissionDeniedError` | a look-only key tried to launch, or a dashboard-only setting |
|
|
123
|
+
| `NotFoundError` | no such machine or project, or not one you can see |
|
|
124
|
+
| `LaunchFailedError` | the machine couldn't start (refunded in full) |
|
|
125
|
+
| `WaitTimeoutError` | `wait_until_running` gave up; the machine may still start |
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from computenexa import NoCapacityError
|
|
129
|
+
|
|
130
|
+
for gpu in ["rtx-4090", "l40s", "a40"]:
|
|
131
|
+
try:
|
|
132
|
+
machine = cnx.launch(gpu, app="chat", hours=1)
|
|
133
|
+
break
|
|
134
|
+
except NoCapacityError:
|
|
135
|
+
continue
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Reads are retried automatically when the API is busy (429) or has a server error. A launch is never retried after
|
|
139
|
+
an uncertain failure, so it can't start two GPUs.
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
| | |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `Client(api_key=...)` or `CNX_API_KEY` | your API key |
|
|
146
|
+
| `Client(base_url=...)` or `CNX_API_URL` | defaults to `https://api.computenexa.com/v1` |
|
|
147
|
+
| `Client(timeout=30, max_retries=3)` | per request |
|
|
148
|
+
|
|
149
|
+
## Help
|
|
150
|
+
|
|
151
|
+
- Guide: <https://app.computenexa.com/help/api>
|
|
152
|
+
- Every operation: <https://app.computenexa.com/help/api/reference>
|
|
153
|
+
- Support: <support@computenexa.com>
|
|
154
|
+
|
|
155
|
+
MIT licensed. © ComputeNexa.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# ComputeNexa Python SDK
|
|
2
|
+
|
|
3
|
+
Launch, use and stop private GPUs on [ComputeNexa](https://computenexa.com) from Python. Each GPU is reserved for
|
|
4
|
+
your team, runs open AI models or your own code, and is paid by the minute from your team's prepaid credits.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install computenexa
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
Create an API key in the dashboard under **API keys** ("Launch and stop" to launch), then:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
export CNX_API_KEY="cnxk_..."
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from computenexa import Client
|
|
20
|
+
|
|
21
|
+
cnx = Client() # reads CNX_API_KEY
|
|
22
|
+
|
|
23
|
+
# Launch an RTX 4090 with JupyterLab and PyTorch for 2 hours; it's stopped when the block ends,
|
|
24
|
+
# even if your code fails, and unused minutes are refunded.
|
|
25
|
+
with cnx.gpu("rtx-4090", app="datascience", hours=2) as machine:
|
|
26
|
+
print(machine.ssh_command) # ssh cnx-7f3a9c@ssh.computenexa.com
|
|
27
|
+
... # your work
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Choose a GPU and an app
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
catalog = cnx.catalog() # live prices and stock; catalog.apps describes each app
|
|
34
|
+
for gpu in catalog.available(app="chat"): # for sale now, cheapest first
|
|
35
|
+
print(gpu.slug, gpu.vram_gb, "GB", gpu.price_per_hour_cents / 100, "$/h")
|
|
36
|
+
|
|
37
|
+
chat = catalog.apps["chat"]
|
|
38
|
+
print(chat.recommended_model(vram_gb=48)) # our model pick for a 48 GB GPU
|
|
39
|
+
print(cnx.image_contents("datascience")) # every package and version installed
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| `app=` | On the launch page | For |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `chat` | Private Chat | chat with open AI models about your documents, in your browser |
|
|
45
|
+
| `imagegen` | Image Generation (ComfyUI) | images with SDXL or FLUX |
|
|
46
|
+
| `modelapi` | Model API (vLLM) | an AI model behind your own API key |
|
|
47
|
+
| `voice` | Voice Agent | speech in, spoken AI reply out |
|
|
48
|
+
| `datascience` | Notebook (Jupyter) | JupyterLab, PyTorch, pandas: analysis, training, fine-tuning |
|
|
49
|
+
| `basic` | Basic (SSH only) | Ubuntu + CUDA for your own code |
|
|
50
|
+
|
|
51
|
+
## Keep files between sessions with projects
|
|
52
|
+
|
|
53
|
+
A project is saved storage: launched with it, a GPU starts with the project's files in `~/work` and saves
|
|
54
|
+
`~/work` back automatically.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
project = cnx.get_or_create_project("titanic-training")
|
|
58
|
+
machine = cnx.launch("l40s", app="datascience", hours=4, project=project, label="nightly training")
|
|
59
|
+
machine.wait_until_running(on_progress=lambda m: print(m.state, m.startup_progress or ""))
|
|
60
|
+
print(machine.ssh_command)
|
|
61
|
+
# ... later
|
|
62
|
+
machine.stop()
|
|
63
|
+
print("refunded", machine.refunded_cents / 100)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Machines
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
cnx.list_instances(active=True) # your running and starting machines
|
|
70
|
+
cnx.list_instances(everyone=True) # the whole team's (owners and admins)
|
|
71
|
+
machine = cnx.get_instance("cnx-7f3a9c")
|
|
72
|
+
machine.extend(hours=1) # same price it launched with
|
|
73
|
+
machine.stop() # stops if running, cancels if still starting
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Account, credits and SSH keys
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
me = cnx.account()
|
|
80
|
+
print(me.email, me.organization.name, me.organization.role, me.balance, me.max_concurrent_gpus)
|
|
81
|
+
for entry in cnx.ledger(limit=20):
|
|
82
|
+
print(entry.created_at, entry.description, entry.amount_cents / 100)
|
|
83
|
+
|
|
84
|
+
cnx.add_ssh_key("Work laptop", open("/Users/me/.ssh/id_ed25519.pub").read()) # the PUBLIC key only
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Errors
|
|
88
|
+
|
|
89
|
+
Every refusal raises a subclass of `computenexa.ComputeNexaError` with a stable `code`, a `message` you can show
|
|
90
|
+
and a `request_id` to quote to support:
|
|
91
|
+
|
|
92
|
+
| Exception | When |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `InsufficientCreditsError` | not enough credits for the launch or extension |
|
|
95
|
+
| `NoCapacityError` | that GPU is fully booked right now: retry or pick another |
|
|
96
|
+
| `GpuLimitReachedError` | your team (or you) already run as many GPUs as allowed |
|
|
97
|
+
| `ProjectInUseError` | another GPU is using the project |
|
|
98
|
+
| `AuthenticationError` | the key is missing, mistyped or revoked |
|
|
99
|
+
| `PermissionDeniedError` | a look-only key tried to launch, or a dashboard-only setting |
|
|
100
|
+
| `NotFoundError` | no such machine or project, or not one you can see |
|
|
101
|
+
| `LaunchFailedError` | the machine couldn't start (refunded in full) |
|
|
102
|
+
| `WaitTimeoutError` | `wait_until_running` gave up; the machine may still start |
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from computenexa import NoCapacityError
|
|
106
|
+
|
|
107
|
+
for gpu in ["rtx-4090", "l40s", "a40"]:
|
|
108
|
+
try:
|
|
109
|
+
machine = cnx.launch(gpu, app="chat", hours=1)
|
|
110
|
+
break
|
|
111
|
+
except NoCapacityError:
|
|
112
|
+
continue
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Reads are retried automatically when the API is busy (429) or has a server error. A launch is never retried after
|
|
116
|
+
an uncertain failure, so it can't start two GPUs.
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
| | |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `Client(api_key=...)` or `CNX_API_KEY` | your API key |
|
|
123
|
+
| `Client(base_url=...)` or `CNX_API_URL` | defaults to `https://api.computenexa.com/v1` |
|
|
124
|
+
| `Client(timeout=30, max_retries=3)` | per request |
|
|
125
|
+
|
|
126
|
+
## Help
|
|
127
|
+
|
|
128
|
+
- Guide: <https://app.computenexa.com/help/api>
|
|
129
|
+
- Every operation: <https://app.computenexa.com/help/api/reference>
|
|
130
|
+
- Support: <support@computenexa.com>
|
|
131
|
+
|
|
132
|
+
MIT licensed. © ComputeNexa.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "computenexa"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
description = "Python client for ComputeNexa: private GPUs for your business, launched and stopped from code."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "ComputeNexa", email = "support@computenexa.com" }]
|
|
9
|
+
maintainers = [{ name = "ComputeNexa", email = "support@computenexa.com" }]
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
dependencies = ["httpx>=0.27,<1"]
|
|
12
|
+
keywords = ["gpu", "cloud", "ai", "private ai", "computenexa", "llm", "inference", "training"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://computenexa.com"
|
|
24
|
+
Documentation = "https://app.computenexa.com/help/api"
|
|
25
|
+
"API reference" = "https://app.computenexa.com/help/api/reference"
|
|
26
|
+
Support = "https://app.computenexa.com/help"
|
|
27
|
+
|
|
28
|
+
[build-system]
|
|
29
|
+
requires = ["hatchling>=1.26"]
|
|
30
|
+
build-backend = "hatchling.build"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/computenexa"]
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = ["pytest>=8", "ruff>=0.6"]
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
testpaths = ["tests"]
|
|
40
|
+
markers = ["integration: talks to a real ComputeNexa API (set CNX_TEST_API_URL and CNX_TEST_API_KEY)"]
|
|
41
|
+
|
|
42
|
+
[tool.ruff]
|
|
43
|
+
line-length = 120
|
|
44
|
+
target-version = "py39"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""ComputeNexa: private GPUs for your business, from Python.
|
|
2
|
+
|
|
3
|
+
from computenexa import Client
|
|
4
|
+
|
|
5
|
+
cnx = Client() # reads CNX_API_KEY
|
|
6
|
+
with cnx.gpu("rtx-4090", app="datascience", hours=2) as machine:
|
|
7
|
+
print(machine.ssh_command)
|
|
8
|
+
|
|
9
|
+
Guide: https://app.computenexa.com/help/api · Reference: https://app.computenexa.com/help/api/reference
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.1"
|
|
13
|
+
|
|
14
|
+
from .client import Client
|
|
15
|
+
from .errors import (
|
|
16
|
+
APIConnectionError,
|
|
17
|
+
AuthenticationError,
|
|
18
|
+
ComputeNexaError,
|
|
19
|
+
ConflictError,
|
|
20
|
+
GpuLimitReachedError,
|
|
21
|
+
InsufficientCreditsError,
|
|
22
|
+
InvalidRequestError,
|
|
23
|
+
LaunchFailedError,
|
|
24
|
+
NoCapacityError,
|
|
25
|
+
NotFoundError,
|
|
26
|
+
PermissionDeniedError,
|
|
27
|
+
ProjectInUseError,
|
|
28
|
+
RateLimitError,
|
|
29
|
+
ServerError,
|
|
30
|
+
WaitTimeoutError,
|
|
31
|
+
)
|
|
32
|
+
from .models import Account, App, Catalog, Gpu, Instance, LedgerEntry, Organization, Project, SshKey
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"APIConnectionError",
|
|
36
|
+
"Account",
|
|
37
|
+
"App",
|
|
38
|
+
"AuthenticationError",
|
|
39
|
+
"Catalog",
|
|
40
|
+
"Client",
|
|
41
|
+
"ComputeNexaError",
|
|
42
|
+
"ConflictError",
|
|
43
|
+
"Gpu",
|
|
44
|
+
"GpuLimitReachedError",
|
|
45
|
+
"Instance",
|
|
46
|
+
"InsufficientCreditsError",
|
|
47
|
+
"InvalidRequestError",
|
|
48
|
+
"LaunchFailedError",
|
|
49
|
+
"LedgerEntry",
|
|
50
|
+
"NoCapacityError",
|
|
51
|
+
"NotFoundError",
|
|
52
|
+
"Organization",
|
|
53
|
+
"PermissionDeniedError",
|
|
54
|
+
"Project",
|
|
55
|
+
"ProjectInUseError",
|
|
56
|
+
"RateLimitError",
|
|
57
|
+
"ServerError",
|
|
58
|
+
"SshKey",
|
|
59
|
+
"WaitTimeoutError",
|
|
60
|
+
]
|