Version bump
This commit is contained in:
54
README.md
54
README.md
@ -172,6 +172,8 @@ import sys
|
||||
# Stream a new command
|
||||
for event in capsule.commands.stream("python", args=["-u", "train.py"]):
|
||||
match event.type:
|
||||
case "start":
|
||||
print(f"PID: {event.pid}")
|
||||
case "stdout":
|
||||
print(event.data, end="")
|
||||
case "stderr":
|
||||
@ -181,8 +183,11 @@ for event in capsule.commands.stream("python", args=["-u", "train.py"]):
|
||||
|
||||
# Connect to a running background process
|
||||
for event in capsule.commands.connect(handle.pid):
|
||||
if event.type == "stdout":
|
||||
print(event.data, end="")
|
||||
match event.type:
|
||||
case "start":
|
||||
print(f"PID: {event.pid}")
|
||||
case "stdout":
|
||||
print(event.data, end="")
|
||||
```
|
||||
|
||||
#### Process Management
|
||||
@ -211,6 +216,7 @@ capsule.files.exists("/app/main.py") # True
|
||||
|
||||
# List directory
|
||||
entries = capsule.files.list("/home/user", depth=1)
|
||||
# FileEntry has: name, type (file/dir), size, modified_at
|
||||
for entry in entries:
|
||||
print(entry.name, entry.type, entry.size)
|
||||
|
||||
@ -289,8 +295,27 @@ value = capsule.git.get_config("user.name", cwd="/app") # str | None
|
||||
|
||||
capsule.git.remote_add("upstream", "https://github.com/org/repo.git", cwd="/app")
|
||||
url = capsule.git.remote_get("origin", cwd="/app") # str | None
|
||||
|
||||
# Reset and restore
|
||||
capsule.git.reset(mode="hard", ref="HEAD~1", cwd="/app")
|
||||
capsule.git.restore(["file.txt"], staged=True, cwd="/app")
|
||||
```
|
||||
|
||||
#### Persistent Credential Store
|
||||
|
||||
For workflows that need repeated authenticated operations, you can persist credentials via the git credential store:
|
||||
|
||||
```python
|
||||
capsule.git.dangerously_authenticate(
|
||||
username="user",
|
||||
password="ghp_token",
|
||||
host="github.com",
|
||||
protocol="https",
|
||||
)
|
||||
```
|
||||
|
||||
> **Warning:** Credentials are written in plaintext inside the capsule and are accessible to any process running there. Prefer per-operation `username`/`password` on `clone`, `push`, and `pull` instead.
|
||||
|
||||
Git errors raise `GitCommandError` (or `GitAuthError` for authentication failures), both inheriting from `GitError`:
|
||||
|
||||
```python
|
||||
@ -308,7 +333,7 @@ except GitAuthError as e:
|
||||
```python
|
||||
import sys
|
||||
|
||||
with capsule.pty(cmd="/bin/bash", cols=120, rows=40, cwd="/home/user") as term:
|
||||
with capsule.pty(cmd="/bin/bash", cols=80, rows=24, cwd="/home/user") as term:
|
||||
term.write(b"ls -la\n")
|
||||
for event in term:
|
||||
if event.type == "output":
|
||||
@ -451,9 +476,10 @@ result = capsule.run_code("print('running on custom template')")
|
||||
| `logs` | `Logs` | `.stdout: list[str]` and `.stderr: list[str]` chunks |
|
||||
| `error` | `ExecutionError \| None` | `.name`, `.value`, `.traceback` |
|
||||
| `execution_count` | `int \| None` | Jupyter cell execution counter |
|
||||
| `timed_out` | `bool` | ``True`` when execution was cut short by the timeout |
|
||||
| `text` | `str \| None` | (property) `text/plain` of the main `execute_result` |
|
||||
|
||||
Each `Result` has typed MIME fields: `text`, `html`, `markdown`, `svg`, `png`, `jpeg`, `pdf`, `latex`, `json`, `javascript`, plus `extra` for unknown types. The `text` field is Jupyter's `text/plain` bundle verbatim — the Python `repr()` of the cell's last expression. So `run_code("'hi'").text` is `"'hi'"` (with quotes), and `run_code("42").text` is `"42"`. This preserves the distinction between the string `'2'` and the int `2`.
|
||||
Each `Result` has typed MIME fields: `text`, `html`, `markdown`, `svg`, `png`, `jpeg`, `gif`, `pdf`, `latex`, `json`, `javascript`, `plotly`, plus `extra` for unknown types. The `text` field is Jupyter's `text/plain` bundle verbatim — the Python `repr()` of the cell's last expression. So `run_code("'hi'").text` is `"'hi'"` (with quotes), and `run_code("42").text` is `"42"`. This preserves the distinction between the string `'2'` and the int `2`.
|
||||
|
||||
### Code Runner + Commands/Files
|
||||
|
||||
@ -527,15 +553,15 @@ The SDK maps server error codes to typed exceptions:
|
||||
```python
|
||||
from wrenn import (
|
||||
WrennError,
|
||||
WrennValidationError, # 400
|
||||
WrennAuthenticationError, # 401
|
||||
WrennForbiddenError, # 403
|
||||
WrennNotFoundError, # 404
|
||||
WrennConflictError, # 409
|
||||
WrennHostHasCapsulesError, # 409 (host has running capsules)
|
||||
WrennAgentError, # 502
|
||||
WrennInternalError, # 500
|
||||
WrennHostUnavailableError, # 503
|
||||
WrennValidationError, # 400
|
||||
WrennAuthenticationError, # 401
|
||||
WrennForbiddenError, # 403
|
||||
WrennNotFoundError, # 404
|
||||
WrennConflictError, # 409
|
||||
WrennHostHasCapsulesError, # 409 (host has running capsules)
|
||||
WrennInternalError, # 500
|
||||
WrennAgentError, # 502
|
||||
WrennHostUnavailableError, # 503
|
||||
)
|
||||
|
||||
try:
|
||||
@ -603,7 +629,7 @@ with WrennClient(api_key="wrn_...") as client:
|
||||
|
||||
# Snapshots
|
||||
template = client.snapshots.create(capsule_id="cl-abc", name="my-snap")
|
||||
templates = client.snapshots.list()
|
||||
templates = client.snapshots.list(type="custom") # optional type filter
|
||||
client.snapshots.delete("my-snap")
|
||||
```
|
||||
|
||||
|
||||
141
api/openapi.yaml
141
api/openapi.yaml
@ -2716,14 +2716,39 @@ paths:
|
||||
tags: [admin]
|
||||
security:
|
||||
- sessionAuth: []
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
default: 1
|
||||
description: Page number for pagination.
|
||||
responses:
|
||||
"200":
|
||||
description: Teams list
|
||||
description: Paginated teams list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items: {type: object}
|
||||
type: object
|
||||
properties:
|
||||
teams:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/AdminTeam"
|
||||
total:
|
||||
type: integer
|
||||
page:
|
||||
type: integer
|
||||
per_page:
|
||||
type: integer
|
||||
total_pages:
|
||||
type: integer
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
|
||||
/v1/admin/teams/{id}/byoc:
|
||||
put:
|
||||
@ -2743,12 +2768,20 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [byoc]
|
||||
required: [enabled]
|
||||
properties:
|
||||
byoc: {type: boolean}
|
||||
enabled:
|
||||
type: boolean
|
||||
description: true to enable BYOC, false to disable.
|
||||
responses:
|
||||
"204":
|
||||
description: Updated
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
|
||||
/v1/admin/teams/{id}:
|
||||
delete:
|
||||
@ -2765,6 +2798,38 @@ paths:
|
||||
responses:
|
||||
"204":
|
||||
description: Deleted
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
/v1/admin/hosts:
|
||||
get:
|
||||
summary: List all hosts (admin)
|
||||
operationId: adminListHosts
|
||||
tags: [admin]
|
||||
security:
|
||||
- sessionAuth: []
|
||||
description: |
|
||||
Returns all hosts across all teams with per-host resource consumption.
|
||||
Includes team name for hosts associated with a team.
|
||||
responses:
|
||||
"200":
|
||||
description: Hosts list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Host"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
|
||||
/v1/admin/users:
|
||||
get:
|
||||
@ -3581,10 +3646,6 @@ components:
|
||||
type: integer
|
||||
memory_mb_reserved:
|
||||
type: integer
|
||||
sampled_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
peaks:
|
||||
type: object
|
||||
description: Maximum values over the last 30 days.
|
||||
@ -3633,10 +3694,6 @@ components:
|
||||
type: integer
|
||||
timeout_sec:
|
||||
type: integer
|
||||
guest_ip:
|
||||
type: string
|
||||
host_ip:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
@ -3661,7 +3718,11 @@ components:
|
||||
agent_version, envd_version) when running.
|
||||
disk_size_mb:
|
||||
type: integer
|
||||
nullable: true
|
||||
description: Maximum disk capacity in MiB.
|
||||
disk_used_mb:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Current disk usage in MiB. Only populated on individual capsule GET; omitted in list responses.
|
||||
|
||||
CreateSnapshotRequest:
|
||||
type: object
|
||||
@ -4013,6 +4074,25 @@ components:
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
team_name:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Team name (included when listing hosts as an admin).
|
||||
running_vcpus:
|
||||
type: integer
|
||||
description: Total vCPUs allocated to running capsules on this host.
|
||||
running_memory_mb:
|
||||
type: integer
|
||||
description: Total memory in MB allocated to running capsules on this host.
|
||||
running_disk_mb:
|
||||
type: integer
|
||||
description: Total disk in MB allocated to running capsules on this host.
|
||||
paused_memory_mb:
|
||||
type: integer
|
||||
description: Total memory in MB allocated to paused capsules on this host.
|
||||
paused_disk_mb:
|
||||
type: integer
|
||||
description: Total disk in MB allocated to paused capsules on this host.
|
||||
|
||||
RefreshHostTokenRequest:
|
||||
type: object
|
||||
@ -4124,6 +4204,39 @@ components:
|
||||
items:
|
||||
$ref: "#/components/schemas/TeamMember"
|
||||
|
||||
AdminTeam:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
slug:
|
||||
type: string
|
||||
is_byoc:
|
||||
type: boolean
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
deleted_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
member_count:
|
||||
type: integer
|
||||
owner_name:
|
||||
type: string
|
||||
owner_email:
|
||||
type: string
|
||||
active_sandbox_count:
|
||||
type: integer
|
||||
channel_count:
|
||||
type: integer
|
||||
running_vcpus:
|
||||
type: integer
|
||||
running_memory_mb:
|
||||
type: integer
|
||||
|
||||
CapsuleMetrics:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "wrenn"
|
||||
version = "0.1.5"
|
||||
version = "0.2.0"
|
||||
description = "Python SDK for Wrenn"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
Reference in New Issue
Block a user