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.
@@ -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,7 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ .venv/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ .ruff_cache/
@@ -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
+ ]