arga-py-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.
- arga_py_sdk-0.1.1/.github/workflows/publish.yml +45 -0
- arga_py_sdk-0.1.1/.gitignore +22 -0
- arga_py_sdk-0.1.1/PKG-INFO +149 -0
- arga_py_sdk-0.1.1/README.md +122 -0
- arga_py_sdk-0.1.1/pyproject.toml +40 -0
- arga_py_sdk-0.1.1/src/arga_sdk/__init__.py +25 -0
- arga_py_sdk-0.1.1/src/arga_sdk/_http.py +116 -0
- arga_py_sdk-0.1.1/src/arga_sdk/client.py +502 -0
- arga_py_sdk-0.1.1/src/arga_sdk/exceptions.py +25 -0
- arga_py_sdk-0.1.1/src/arga_sdk/types.py +94 -0
- arga_py_sdk-0.1.1/tests/__init__.py +0 -0
- arga_py_sdk-0.1.1/tests/conftest.py +123 -0
- arga_py_sdk-0.1.1/tests/test_errors.py +156 -0
- arga_py_sdk-0.1.1/tests/test_runs.py +259 -0
- arga_py_sdk-0.1.1/tests/test_scenarios.py +171 -0
- arga_py_sdk-0.1.1/tests/test_twins.py +199 -0
- arga_py_sdk-0.1.1/uv.lock +436 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
|
|
19
|
+
- name: Install build dependencies
|
|
20
|
+
run: pip install hatchling build
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: python -m build
|
|
24
|
+
|
|
25
|
+
- name: Upload dist artifacts
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: dist
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
needs: build
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
environment: pypi
|
|
35
|
+
permissions:
|
|
36
|
+
id-token: write
|
|
37
|
+
steps:
|
|
38
|
+
- name: Download dist artifacts
|
|
39
|
+
uses: actions/download-artifact@v4
|
|
40
|
+
with:
|
|
41
|
+
name: dist
|
|
42
|
+
path: dist/
|
|
43
|
+
|
|
44
|
+
- name: Publish to PyPI
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arga-py-sdk
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python SDK for the Arga API
|
|
5
|
+
Project-URL: Documentation, https://docs.argalabs.com
|
|
6
|
+
Project-URL: Repository, https://github.com/ArgaLabs/arga-python-sdk
|
|
7
|
+
Author-email: Arga Labs <support@argalabs.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx-sse>=0.4.0
|
|
20
|
+
Requires-Dist: httpx>=0.25.0
|
|
21
|
+
Requires-Dist: pydantic>=2.0.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
25
|
+
Requires-Dist: respx; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Arga Python SDK
|
|
29
|
+
|
|
30
|
+
Typed Python client for the [Arga](https://argalabs.com) API. Supports both synchronous and asynchronous usage.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install arga-sdk
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from arga_sdk import Arga
|
|
42
|
+
|
|
43
|
+
client = Arga(api_key="arga_...")
|
|
44
|
+
|
|
45
|
+
# Create a URL run with service twins
|
|
46
|
+
run = client.runs.create_url_run(
|
|
47
|
+
url="https://staging.myapp.com",
|
|
48
|
+
twins=["stripe", "slack"],
|
|
49
|
+
)
|
|
50
|
+
print(run.run_id, run.status)
|
|
51
|
+
|
|
52
|
+
# Poll until the run completes
|
|
53
|
+
detail = client.runs.wait(run.run_id, timeout=300)
|
|
54
|
+
print(detail.status, detail.results_json)
|
|
55
|
+
|
|
56
|
+
# Stream live results
|
|
57
|
+
for event in client.runs.stream_results(run.run_id):
|
|
58
|
+
print(event)
|
|
59
|
+
|
|
60
|
+
# Cancel a run
|
|
61
|
+
client.runs.cancel(run.run_id)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Async Usage
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import asyncio
|
|
68
|
+
from arga_sdk import AsyncArga
|
|
69
|
+
|
|
70
|
+
async def main():
|
|
71
|
+
client = AsyncArga(api_key="arga_...")
|
|
72
|
+
|
|
73
|
+
run = await client.runs.create_url_run(url="https://staging.myapp.com")
|
|
74
|
+
|
|
75
|
+
# Stream results
|
|
76
|
+
async for event in client.runs.stream_results(run.run_id):
|
|
77
|
+
print(event)
|
|
78
|
+
|
|
79
|
+
# Wait for completion
|
|
80
|
+
detail = await client.runs.wait(run.run_id)
|
|
81
|
+
print(detail.status)
|
|
82
|
+
|
|
83
|
+
await client.close()
|
|
84
|
+
|
|
85
|
+
asyncio.run(main())
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Context Manager
|
|
89
|
+
|
|
90
|
+
Both clients support context managers to ensure proper cleanup:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
with Arga(api_key="arga_...") as client:
|
|
94
|
+
run = client.runs.create_url_run(url="https://staging.myapp.com")
|
|
95
|
+
|
|
96
|
+
async with AsyncArga(api_key="arga_...") as client:
|
|
97
|
+
run = await client.runs.create_url_run(url="https://staging.myapp.com")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Available Methods
|
|
101
|
+
|
|
102
|
+
### Runs
|
|
103
|
+
|
|
104
|
+
| Method | Description |
|
|
105
|
+
|--------|-------------|
|
|
106
|
+
| `client.runs.create_url_run(url, ...)` | Test a live URL with browser validation |
|
|
107
|
+
| `client.runs.create_pr_run(repo, ...)` | Validate code changes from a PR or branch |
|
|
108
|
+
| `client.runs.create_agent_run(...)` | Deploy an autonomous agent for exploration |
|
|
109
|
+
| `client.runs.get(run_id)` | Get full run details |
|
|
110
|
+
| `client.runs.stream_results(run_id)` | Stream SSE result events |
|
|
111
|
+
| `client.runs.cancel(run_id)` | Cancel a running run |
|
|
112
|
+
| `client.runs.wait(run_id, ...)` | Poll until terminal status |
|
|
113
|
+
|
|
114
|
+
### Twins
|
|
115
|
+
|
|
116
|
+
| Method | Description |
|
|
117
|
+
|--------|-------------|
|
|
118
|
+
| `client.twins.list()` | List available service twins |
|
|
119
|
+
| `client.twins.provision(twins, ...)` | Provision twin instances |
|
|
120
|
+
| `client.twins.get_status(run_id)` | Get provisioning status |
|
|
121
|
+
| `client.twins.extend(run_id, ...)` | Extend twin TTL |
|
|
122
|
+
|
|
123
|
+
### Scenarios
|
|
124
|
+
|
|
125
|
+
| Method | Description |
|
|
126
|
+
|--------|-------------|
|
|
127
|
+
| `client.scenarios.create(name, ...)` | Create a test scenario |
|
|
128
|
+
| `client.scenarios.list(...)` | List scenarios (with optional filters) |
|
|
129
|
+
| `client.scenarios.get(scenario_id)` | Get a scenario by ID |
|
|
130
|
+
|
|
131
|
+
## Error Handling
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from arga_sdk import Arga, ArgaAPIError, ArgaError
|
|
135
|
+
|
|
136
|
+
client = Arga(api_key="arga_...")
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
run = client.runs.get("nonexistent-id")
|
|
140
|
+
except ArgaAPIError as e:
|
|
141
|
+
print(e.status_code) # e.g. 404
|
|
142
|
+
print(e.message)
|
|
143
|
+
except ArgaError as e:
|
|
144
|
+
print(e.message)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Documentation
|
|
148
|
+
|
|
149
|
+
Full API documentation is available at [docs.argalabs.com](https://docs.argalabs.com).
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Arga Python SDK
|
|
2
|
+
|
|
3
|
+
Typed Python client for the [Arga](https://argalabs.com) API. Supports both synchronous and asynchronous usage.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install arga-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from arga_sdk import Arga
|
|
15
|
+
|
|
16
|
+
client = Arga(api_key="arga_...")
|
|
17
|
+
|
|
18
|
+
# Create a URL run with service twins
|
|
19
|
+
run = client.runs.create_url_run(
|
|
20
|
+
url="https://staging.myapp.com",
|
|
21
|
+
twins=["stripe", "slack"],
|
|
22
|
+
)
|
|
23
|
+
print(run.run_id, run.status)
|
|
24
|
+
|
|
25
|
+
# Poll until the run completes
|
|
26
|
+
detail = client.runs.wait(run.run_id, timeout=300)
|
|
27
|
+
print(detail.status, detail.results_json)
|
|
28
|
+
|
|
29
|
+
# Stream live results
|
|
30
|
+
for event in client.runs.stream_results(run.run_id):
|
|
31
|
+
print(event)
|
|
32
|
+
|
|
33
|
+
# Cancel a run
|
|
34
|
+
client.runs.cancel(run.run_id)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Async Usage
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import asyncio
|
|
41
|
+
from arga_sdk import AsyncArga
|
|
42
|
+
|
|
43
|
+
async def main():
|
|
44
|
+
client = AsyncArga(api_key="arga_...")
|
|
45
|
+
|
|
46
|
+
run = await client.runs.create_url_run(url="https://staging.myapp.com")
|
|
47
|
+
|
|
48
|
+
# Stream results
|
|
49
|
+
async for event in client.runs.stream_results(run.run_id):
|
|
50
|
+
print(event)
|
|
51
|
+
|
|
52
|
+
# Wait for completion
|
|
53
|
+
detail = await client.runs.wait(run.run_id)
|
|
54
|
+
print(detail.status)
|
|
55
|
+
|
|
56
|
+
await client.close()
|
|
57
|
+
|
|
58
|
+
asyncio.run(main())
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Context Manager
|
|
62
|
+
|
|
63
|
+
Both clients support context managers to ensure proper cleanup:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
with Arga(api_key="arga_...") as client:
|
|
67
|
+
run = client.runs.create_url_run(url="https://staging.myapp.com")
|
|
68
|
+
|
|
69
|
+
async with AsyncArga(api_key="arga_...") as client:
|
|
70
|
+
run = await client.runs.create_url_run(url="https://staging.myapp.com")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Available Methods
|
|
74
|
+
|
|
75
|
+
### Runs
|
|
76
|
+
|
|
77
|
+
| Method | Description |
|
|
78
|
+
|--------|-------------|
|
|
79
|
+
| `client.runs.create_url_run(url, ...)` | Test a live URL with browser validation |
|
|
80
|
+
| `client.runs.create_pr_run(repo, ...)` | Validate code changes from a PR or branch |
|
|
81
|
+
| `client.runs.create_agent_run(...)` | Deploy an autonomous agent for exploration |
|
|
82
|
+
| `client.runs.get(run_id)` | Get full run details |
|
|
83
|
+
| `client.runs.stream_results(run_id)` | Stream SSE result events |
|
|
84
|
+
| `client.runs.cancel(run_id)` | Cancel a running run |
|
|
85
|
+
| `client.runs.wait(run_id, ...)` | Poll until terminal status |
|
|
86
|
+
|
|
87
|
+
### Twins
|
|
88
|
+
|
|
89
|
+
| Method | Description |
|
|
90
|
+
|--------|-------------|
|
|
91
|
+
| `client.twins.list()` | List available service twins |
|
|
92
|
+
| `client.twins.provision(twins, ...)` | Provision twin instances |
|
|
93
|
+
| `client.twins.get_status(run_id)` | Get provisioning status |
|
|
94
|
+
| `client.twins.extend(run_id, ...)` | Extend twin TTL |
|
|
95
|
+
|
|
96
|
+
### Scenarios
|
|
97
|
+
|
|
98
|
+
| Method | Description |
|
|
99
|
+
|--------|-------------|
|
|
100
|
+
| `client.scenarios.create(name, ...)` | Create a test scenario |
|
|
101
|
+
| `client.scenarios.list(...)` | List scenarios (with optional filters) |
|
|
102
|
+
| `client.scenarios.get(scenario_id)` | Get a scenario by ID |
|
|
103
|
+
|
|
104
|
+
## Error Handling
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from arga_sdk import Arga, ArgaAPIError, ArgaError
|
|
108
|
+
|
|
109
|
+
client = Arga(api_key="arga_...")
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
run = client.runs.get("nonexistent-id")
|
|
113
|
+
except ArgaAPIError as e:
|
|
114
|
+
print(e.status_code) # e.g. 404
|
|
115
|
+
print(e.message)
|
|
116
|
+
except ArgaError as e:
|
|
117
|
+
print(e.message)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Documentation
|
|
121
|
+
|
|
122
|
+
Full API documentation is available at [docs.argalabs.com](https://docs.argalabs.com).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "arga-py-sdk"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Python SDK for the Arga API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Arga Labs", email = "support@argalabs.com" },
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"httpx>=0.25.0",
|
|
28
|
+
"httpx-sse>=0.4.0",
|
|
29
|
+
"pydantic>=2.0.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = ["pytest", "pytest-asyncio", "respx"]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Documentation = "https://docs.argalabs.com"
|
|
37
|
+
Repository = "https://github.com/ArgaLabs/arga-python-sdk"
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.wheel]
|
|
40
|
+
packages = ["src/arga_sdk"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Arga Python SDK — typed client for the Arga API."""
|
|
2
|
+
|
|
3
|
+
from arga_sdk.client import Arga, AsyncArga
|
|
4
|
+
from arga_sdk.exceptions import ArgaAPIError, ArgaError
|
|
5
|
+
from arga_sdk.types import (
|
|
6
|
+
Run,
|
|
7
|
+
RunDetail,
|
|
8
|
+
Scenario,
|
|
9
|
+
Twin,
|
|
10
|
+
TwinInstance,
|
|
11
|
+
TwinProvisionStatus,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Arga",
|
|
16
|
+
"AsyncArga",
|
|
17
|
+
"ArgaAPIError",
|
|
18
|
+
"ArgaError",
|
|
19
|
+
"Run",
|
|
20
|
+
"RunDetail",
|
|
21
|
+
"Scenario",
|
|
22
|
+
"Twin",
|
|
23
|
+
"TwinInstance",
|
|
24
|
+
"TwinProvisionStatus",
|
|
25
|
+
]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Iterator, AsyncIterator
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
import httpx_sse
|
|
7
|
+
|
|
8
|
+
from arga_sdk.exceptions import ArgaAPIError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _raise_for_status(response: httpx.Response) -> None:
|
|
12
|
+
"""Raise ArgaAPIError for non-2xx responses."""
|
|
13
|
+
if response.is_success:
|
|
14
|
+
return
|
|
15
|
+
try:
|
|
16
|
+
body = response.json()
|
|
17
|
+
message = body.get("detail", body.get("message", response.text))
|
|
18
|
+
except Exception:
|
|
19
|
+
message = response.text
|
|
20
|
+
raise ArgaAPIError(
|
|
21
|
+
status_code=response.status_code,
|
|
22
|
+
message=str(message),
|
|
23
|
+
response=response,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SyncHTTPClient:
|
|
28
|
+
"""Synchronous HTTP client wrapper around httpx."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, base_url: str, api_key: str, timeout: float = 60.0) -> None:
|
|
31
|
+
self._client = httpx.Client(
|
|
32
|
+
base_url=base_url,
|
|
33
|
+
headers={
|
|
34
|
+
"Authorization": f"Bearer {api_key}",
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
},
|
|
37
|
+
timeout=timeout,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def get(self, path: str, params: dict[str, Any] | None = None) -> Any:
|
|
41
|
+
response = self._client.get(path, params=params)
|
|
42
|
+
_raise_for_status(response)
|
|
43
|
+
return response.json()
|
|
44
|
+
|
|
45
|
+
def post(self, path: str, json: dict[str, Any] | None = None) -> Any:
|
|
46
|
+
response = self._client.post(path, json=json)
|
|
47
|
+
_raise_for_status(response)
|
|
48
|
+
return response.json()
|
|
49
|
+
|
|
50
|
+
def stream_sse(self, path: str) -> Iterator[dict[str, Any]]:
|
|
51
|
+
"""Stream SSE events from a GET endpoint."""
|
|
52
|
+
with httpx_sse.connect_sse(
|
|
53
|
+
self._client, "GET", path
|
|
54
|
+
) as event_source:
|
|
55
|
+
for sse in event_source.iter_sse():
|
|
56
|
+
import json as _json
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
data = _json.loads(sse.data)
|
|
60
|
+
except (ValueError, TypeError):
|
|
61
|
+
data = sse.data
|
|
62
|
+
yield {
|
|
63
|
+
"event": sse.event,
|
|
64
|
+
"data": data,
|
|
65
|
+
"id": sse.id,
|
|
66
|
+
"retry": sse.retry,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def close(self) -> None:
|
|
70
|
+
self._client.close()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AsyncHTTPClient:
|
|
74
|
+
"""Asynchronous HTTP client wrapper around httpx."""
|
|
75
|
+
|
|
76
|
+
def __init__(self, base_url: str, api_key: str, timeout: float = 60.0) -> None:
|
|
77
|
+
self._client = httpx.AsyncClient(
|
|
78
|
+
base_url=base_url,
|
|
79
|
+
headers={
|
|
80
|
+
"Authorization": f"Bearer {api_key}",
|
|
81
|
+
"Content-Type": "application/json",
|
|
82
|
+
},
|
|
83
|
+
timeout=timeout,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
async def get(self, path: str, params: dict[str, Any] | None = None) -> Any:
|
|
87
|
+
response = await self._client.get(path, params=params)
|
|
88
|
+
_raise_for_status(response)
|
|
89
|
+
return response.json()
|
|
90
|
+
|
|
91
|
+
async def post(self, path: str, json: dict[str, Any] | None = None) -> Any:
|
|
92
|
+
response = await self._client.post(path, json=json)
|
|
93
|
+
_raise_for_status(response)
|
|
94
|
+
return response.json()
|
|
95
|
+
|
|
96
|
+
async def stream_sse(self, path: str) -> AsyncIterator[dict[str, Any]]:
|
|
97
|
+
"""Stream SSE events from a GET endpoint."""
|
|
98
|
+
async with httpx_sse.aconnect_sse(
|
|
99
|
+
self._client, "GET", path
|
|
100
|
+
) as event_source:
|
|
101
|
+
async for sse in event_source.aiter_sse():
|
|
102
|
+
import json as _json
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
data = _json.loads(sse.data)
|
|
106
|
+
except (ValueError, TypeError):
|
|
107
|
+
data = sse.data
|
|
108
|
+
yield {
|
|
109
|
+
"event": sse.event,
|
|
110
|
+
"data": data,
|
|
111
|
+
"id": sse.id,
|
|
112
|
+
"retry": sse.retry,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async def close(self) -> None:
|
|
116
|
+
await self._client.aclose()
|