syfthub-sdk 0.1.0__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.
- syfthub_sdk-0.1.0/.gitignore +197 -0
- syfthub_sdk-0.1.0/CHANGELOG.md +43 -0
- syfthub_sdk-0.1.0/PKG-INFO +233 -0
- syfthub_sdk-0.1.0/README.md +206 -0
- syfthub_sdk-0.1.0/examples/demo_workflow.py +440 -0
- syfthub_sdk-0.1.0/examples/simple_example.py +79 -0
- syfthub_sdk-0.1.0/pyproject.toml +68 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/__init__.py +152 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/_http.py +327 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/_pagination.py +133 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/accounting.py +611 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/auth.py +371 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/chat.py +811 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/client.py +311 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/exceptions.py +255 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/hub.py +239 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/models.py +424 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/my_endpoints.py +330 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/py.typed +0 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/syftai.py +389 -0
- syfthub_sdk-0.1.0/src/syfthub_sdk/users.py +138 -0
- syfthub_sdk-0.1.0/tests/__init__.py +0 -0
- syfthub_sdk-0.1.0/tests/conftest.py +32 -0
- syfthub_sdk-0.1.0/tests/integration/__init__.py +1 -0
- syfthub_sdk-0.1.0/tests/integration/conftest.py +180 -0
- syfthub_sdk-0.1.0/tests/integration/test_auth.py +281 -0
- syfthub_sdk-0.1.0/tests/integration/test_hub.py +307 -0
- syfthub_sdk-0.1.0/tests/integration/test_my_endpoints.py +438 -0
- syfthub_sdk-0.1.0/tests/integration/test_users.py +153 -0
- syfthub_sdk-0.1.0/tests/unit/__init__.py +1 -0
- syfthub_sdk-0.1.0/tests/unit/test_chat.py +525 -0
- syfthub_sdk-0.1.0/tests/unit/test_syftai.py +448 -0
- syfthub_sdk-0.1.0/uv.lock +674 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
# Python lib directories (but not frontend/src/lib/)
|
|
18
|
+
/lib/
|
|
19
|
+
lib64/
|
|
20
|
+
!frontend/src/lib/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
share/python-wheels/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.installed.cfg
|
|
28
|
+
*.egg
|
|
29
|
+
MANIFEST
|
|
30
|
+
|
|
31
|
+
# PyInstaller
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
.python-version
|
|
87
|
+
|
|
88
|
+
# pipenv
|
|
89
|
+
Pipfile.lock
|
|
90
|
+
|
|
91
|
+
# poetry
|
|
92
|
+
poetry.lock
|
|
93
|
+
|
|
94
|
+
# pdm
|
|
95
|
+
.pdm.toml
|
|
96
|
+
.pdm-python
|
|
97
|
+
.pdm-build/
|
|
98
|
+
|
|
99
|
+
# PEP 582
|
|
100
|
+
__pypackages__/
|
|
101
|
+
|
|
102
|
+
# Celery stuff
|
|
103
|
+
celerybeat-schedule
|
|
104
|
+
celerybeat.pid
|
|
105
|
+
|
|
106
|
+
# SageMath parsed files
|
|
107
|
+
*.sage.py
|
|
108
|
+
|
|
109
|
+
# Environments
|
|
110
|
+
.env
|
|
111
|
+
.venv
|
|
112
|
+
env/
|
|
113
|
+
venv/
|
|
114
|
+
ENV/
|
|
115
|
+
env.bak/
|
|
116
|
+
venv.bak/
|
|
117
|
+
|
|
118
|
+
# Spyder project settings
|
|
119
|
+
.spyderproject
|
|
120
|
+
.spyproject
|
|
121
|
+
|
|
122
|
+
# Rope project settings
|
|
123
|
+
.ropeproject
|
|
124
|
+
|
|
125
|
+
# mkdocs documentation
|
|
126
|
+
/site
|
|
127
|
+
|
|
128
|
+
# mypy
|
|
129
|
+
.mypy_cache/
|
|
130
|
+
.dmypy.json
|
|
131
|
+
dmypy.json
|
|
132
|
+
|
|
133
|
+
# Pyre type checker
|
|
134
|
+
.pyre/
|
|
135
|
+
|
|
136
|
+
# pytype static type analyzer
|
|
137
|
+
.pytype/
|
|
138
|
+
|
|
139
|
+
# Cython debug symbols
|
|
140
|
+
cython_debug/
|
|
141
|
+
|
|
142
|
+
# PyCharm
|
|
143
|
+
.idea/
|
|
144
|
+
|
|
145
|
+
# VS Code
|
|
146
|
+
.vscode/
|
|
147
|
+
|
|
148
|
+
# macOS
|
|
149
|
+
.DS_Store
|
|
150
|
+
|
|
151
|
+
# Windows
|
|
152
|
+
Thumbs.db
|
|
153
|
+
ehthumbs.db
|
|
154
|
+
|
|
155
|
+
# uv
|
|
156
|
+
backend/uv.lock
|
|
157
|
+
|
|
158
|
+
# ruff
|
|
159
|
+
.ruff_cache/
|
|
160
|
+
|
|
161
|
+
# Local data directory
|
|
162
|
+
data/
|
|
163
|
+
backend/data/
|
|
164
|
+
|
|
165
|
+
# RSA keys (auto-generated for multi-worker support)
|
|
166
|
+
# These should NEVER be committed to version control
|
|
167
|
+
**/rsa_keys/
|
|
168
|
+
*.pem
|
|
169
|
+
|
|
170
|
+
# Backend-specific ignores
|
|
171
|
+
backend/.coverage
|
|
172
|
+
backend/coverage.xml
|
|
173
|
+
backend/htmlcov/
|
|
174
|
+
backend/.pytest_cache/
|
|
175
|
+
backend/.mypy_cache/
|
|
176
|
+
backend/.ruff_cache/
|
|
177
|
+
backend/.venv/
|
|
178
|
+
backend/.env
|
|
179
|
+
backend/*.db
|
|
180
|
+
backend/syfthub.db
|
|
181
|
+
|
|
182
|
+
# Frontend
|
|
183
|
+
frontend/node_modules/
|
|
184
|
+
frontend/dist/
|
|
185
|
+
frontend/build/
|
|
186
|
+
frontend/.env*.local
|
|
187
|
+
frontend/.vite/
|
|
188
|
+
frontend/playwright-report/
|
|
189
|
+
frontend/test-results/
|
|
190
|
+
frontend/coverage/
|
|
191
|
+
frontend/.nyc_output/
|
|
192
|
+
frontend/.eslintcache
|
|
193
|
+
frontend/.next/
|
|
194
|
+
frontend/.nuxt/
|
|
195
|
+
frontend/out/
|
|
196
|
+
frontend/storybook-static/
|
|
197
|
+
frontend/tsconfig.tsbuildinfo
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the SyftHub Python SDK will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - Unreleased
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Initial release of the SyftHub Python SDK
|
|
15
|
+
- `SyftHubClient` class for API interactions
|
|
16
|
+
- Authentication via API key
|
|
17
|
+
- Resource APIs:
|
|
18
|
+
- `auth` - Authentication and token management
|
|
19
|
+
- `users` - User management and profiles
|
|
20
|
+
- `hub` - Endpoint discovery and search
|
|
21
|
+
- `chat` - Chat completions API
|
|
22
|
+
- `accounting` - Usage tracking and billing information
|
|
23
|
+
- `my_endpoints` - Manage user's own endpoints
|
|
24
|
+
- `syftai` - SyftAI-specific features
|
|
25
|
+
- Automatic pagination handling with async iterator support
|
|
26
|
+
- Comprehensive error handling with typed exceptions:
|
|
27
|
+
- `SyftHubError` - Base exception class
|
|
28
|
+
- `AuthenticationError` - Authentication failures
|
|
29
|
+
- `RateLimitError` - Rate limit exceeded
|
|
30
|
+
- `NotFoundError` - Resource not found
|
|
31
|
+
- `ValidationError` - Request validation failures
|
|
32
|
+
- Full type hints for IDE support and type checking
|
|
33
|
+
- Async HTTP client built on `httpx`
|
|
34
|
+
- Pydantic models for request/response validation
|
|
35
|
+
|
|
36
|
+
### Dependencies
|
|
37
|
+
|
|
38
|
+
- Python 3.10+
|
|
39
|
+
- httpx >= 0.27
|
|
40
|
+
- pydantic >= 2.0
|
|
41
|
+
|
|
42
|
+
[Unreleased]: https://github.com/OpenMined/syfthub/compare/python-sdk/v0.1.0...HEAD
|
|
43
|
+
[0.1.0]: https://github.com/OpenMined/syfthub/releases/tag/python-sdk/v0.1.0
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: syfthub-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for interacting with SyftHub API
|
|
5
|
+
Author: SyftHub Team
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: api,client,sdk,syfthub
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx>=0.27
|
|
18
|
+
Requires-Dist: pydantic>=2.0
|
|
19
|
+
Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# SyftHub SDK
|
|
29
|
+
|
|
30
|
+
Python SDK for interacting with the SyftHub API programmatically.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Using pip
|
|
36
|
+
pip install syfthub-sdk
|
|
37
|
+
|
|
38
|
+
# Using uv
|
|
39
|
+
uv add syfthub-sdk
|
|
40
|
+
|
|
41
|
+
# From source
|
|
42
|
+
cd sdk
|
|
43
|
+
uv sync
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from syfthub_sdk import SyftHubClient
|
|
50
|
+
|
|
51
|
+
# Initialize client
|
|
52
|
+
client = SyftHubClient(base_url="https://hub.syft.com")
|
|
53
|
+
|
|
54
|
+
# Register a new user
|
|
55
|
+
user = client.auth.register(
|
|
56
|
+
username="john",
|
|
57
|
+
email="john@example.com",
|
|
58
|
+
password="secret123",
|
|
59
|
+
full_name="John Doe"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Login
|
|
63
|
+
user = client.auth.login(username="john", password="secret123")
|
|
64
|
+
print(f"Logged in as {user.username}")
|
|
65
|
+
|
|
66
|
+
# Get current user
|
|
67
|
+
me = client.auth.me()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Managing Your Endpoints
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
# List your endpoints (with lazy pagination)
|
|
74
|
+
for endpoint in client.my_endpoints.list():
|
|
75
|
+
print(f"{endpoint.name} ({endpoint.visibility})")
|
|
76
|
+
|
|
77
|
+
# Get just the first page
|
|
78
|
+
first_page = client.my_endpoints.list().first_page()
|
|
79
|
+
|
|
80
|
+
# Create an endpoint
|
|
81
|
+
endpoint = client.my_endpoints.create(
|
|
82
|
+
name="My Cool API",
|
|
83
|
+
visibility="public",
|
|
84
|
+
description="A really cool API",
|
|
85
|
+
readme="# My API\n\nThis is my API documentation."
|
|
86
|
+
)
|
|
87
|
+
print(f"Created: {endpoint.slug}")
|
|
88
|
+
|
|
89
|
+
# Update an endpoint
|
|
90
|
+
endpoint = client.my_endpoints.update(
|
|
91
|
+
endpoint_id=endpoint.id,
|
|
92
|
+
description="Updated description"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Delete an endpoint
|
|
96
|
+
client.my_endpoints.delete(endpoint_id=endpoint.id)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Browsing the Hub
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
# Browse public endpoints
|
|
103
|
+
for endpoint in client.hub.browse():
|
|
104
|
+
print(f"{endpoint.path}: {endpoint.name}")
|
|
105
|
+
|
|
106
|
+
# Get trending endpoints
|
|
107
|
+
for endpoint in client.hub.trending(min_stars=10):
|
|
108
|
+
print(f"{endpoint.name} - {endpoint.stars_count} stars")
|
|
109
|
+
|
|
110
|
+
# Get a specific endpoint by path
|
|
111
|
+
endpoint = client.hub.get("alice/cool-api")
|
|
112
|
+
print(endpoint.readme)
|
|
113
|
+
|
|
114
|
+
# Star/unstar endpoints (requires auth)
|
|
115
|
+
client.hub.star("alice/cool-api")
|
|
116
|
+
client.hub.unstar("alice/cool-api")
|
|
117
|
+
|
|
118
|
+
# Check if you've starred an endpoint
|
|
119
|
+
if client.hub.is_starred("alice/cool-api"):
|
|
120
|
+
print("You've starred this!")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## User Profile
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
# Update profile
|
|
127
|
+
user = client.users.update(
|
|
128
|
+
full_name="John D.",
|
|
129
|
+
avatar_url="https://example.com/avatar.png"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Check username availability
|
|
133
|
+
if client.users.check_username("newusername"):
|
|
134
|
+
print("Username is available!")
|
|
135
|
+
|
|
136
|
+
# Change password
|
|
137
|
+
client.auth.change_password(
|
|
138
|
+
current_password="old123",
|
|
139
|
+
new_password="new456"
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Accounting
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
# Get account balance
|
|
147
|
+
balance = client.accounting.balance()
|
|
148
|
+
print(f"Credits: {balance.credits} {balance.currency}")
|
|
149
|
+
|
|
150
|
+
# List transactions
|
|
151
|
+
for tx in client.accounting.transactions():
|
|
152
|
+
print(f"{tx.created_at}: {tx.amount} - {tx.description}")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Token Persistence
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# Get tokens for saving
|
|
159
|
+
tokens = client.get_tokens()
|
|
160
|
+
if tokens:
|
|
161
|
+
# Save to file, database, etc.
|
|
162
|
+
save_tokens(tokens.access_token, tokens.refresh_token)
|
|
163
|
+
|
|
164
|
+
# Later, restore session
|
|
165
|
+
from syfthub_sdk import AuthTokens
|
|
166
|
+
|
|
167
|
+
tokens = AuthTokens(
|
|
168
|
+
access_token=load_access_token(),
|
|
169
|
+
refresh_token=load_refresh_token()
|
|
170
|
+
)
|
|
171
|
+
client.set_tokens(tokens)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Environment Variables
|
|
175
|
+
|
|
176
|
+
| Variable | Description |
|
|
177
|
+
|----------|-------------|
|
|
178
|
+
| `SYFTHUB_URL` | SyftHub API base URL |
|
|
179
|
+
| `SYFTHUB_ACCOUNTING_URL` | Accounting service URL |
|
|
180
|
+
| `SYFTHUB_ACCOUNTING_EMAIL` | Accounting auth email |
|
|
181
|
+
| `SYFTHUB_ACCOUNTING_PASSWORD` | Accounting auth password |
|
|
182
|
+
|
|
183
|
+
## Error Handling
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from syfthub_sdk import (
|
|
187
|
+
SyftHubError,
|
|
188
|
+
AuthenticationError,
|
|
189
|
+
AuthorizationError,
|
|
190
|
+
NotFoundError,
|
|
191
|
+
ValidationError,
|
|
192
|
+
ConfigurationError,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
client.auth.login(username="john", password="wrong")
|
|
197
|
+
except AuthenticationError as e:
|
|
198
|
+
print(f"Login failed: {e}")
|
|
199
|
+
except SyftHubError as e:
|
|
200
|
+
print(f"API error [{e.status_code}]: {e.message}")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Context Manager
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
with SyftHubClient(base_url="https://hub.syft.com") as client:
|
|
207
|
+
client.auth.login(username="john", password="secret123")
|
|
208
|
+
# ... do work ...
|
|
209
|
+
# Client is automatically closed
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Pagination
|
|
213
|
+
|
|
214
|
+
All list methods return a `PageIterator` for lazy pagination:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# Iterate through all items (fetches pages as needed)
|
|
218
|
+
for endpoint in client.my_endpoints.list():
|
|
219
|
+
print(endpoint.name)
|
|
220
|
+
|
|
221
|
+
# Get just the first page
|
|
222
|
+
first_page = client.my_endpoints.list().first_page()
|
|
223
|
+
|
|
224
|
+
# Get all items as a list
|
|
225
|
+
all_items = client.my_endpoints.list().all()
|
|
226
|
+
|
|
227
|
+
# Get first N items
|
|
228
|
+
top_10 = client.my_endpoints.list().take(10)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# SyftHub SDK
|
|
2
|
+
|
|
3
|
+
Python SDK for interacting with the SyftHub API programmatically.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Using pip
|
|
9
|
+
pip install syfthub-sdk
|
|
10
|
+
|
|
11
|
+
# Using uv
|
|
12
|
+
uv add syfthub-sdk
|
|
13
|
+
|
|
14
|
+
# From source
|
|
15
|
+
cd sdk
|
|
16
|
+
uv sync
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from syfthub_sdk import SyftHubClient
|
|
23
|
+
|
|
24
|
+
# Initialize client
|
|
25
|
+
client = SyftHubClient(base_url="https://hub.syft.com")
|
|
26
|
+
|
|
27
|
+
# Register a new user
|
|
28
|
+
user = client.auth.register(
|
|
29
|
+
username="john",
|
|
30
|
+
email="john@example.com",
|
|
31
|
+
password="secret123",
|
|
32
|
+
full_name="John Doe"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Login
|
|
36
|
+
user = client.auth.login(username="john", password="secret123")
|
|
37
|
+
print(f"Logged in as {user.username}")
|
|
38
|
+
|
|
39
|
+
# Get current user
|
|
40
|
+
me = client.auth.me()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Managing Your Endpoints
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# List your endpoints (with lazy pagination)
|
|
47
|
+
for endpoint in client.my_endpoints.list():
|
|
48
|
+
print(f"{endpoint.name} ({endpoint.visibility})")
|
|
49
|
+
|
|
50
|
+
# Get just the first page
|
|
51
|
+
first_page = client.my_endpoints.list().first_page()
|
|
52
|
+
|
|
53
|
+
# Create an endpoint
|
|
54
|
+
endpoint = client.my_endpoints.create(
|
|
55
|
+
name="My Cool API",
|
|
56
|
+
visibility="public",
|
|
57
|
+
description="A really cool API",
|
|
58
|
+
readme="# My API\n\nThis is my API documentation."
|
|
59
|
+
)
|
|
60
|
+
print(f"Created: {endpoint.slug}")
|
|
61
|
+
|
|
62
|
+
# Update an endpoint
|
|
63
|
+
endpoint = client.my_endpoints.update(
|
|
64
|
+
endpoint_id=endpoint.id,
|
|
65
|
+
description="Updated description"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Delete an endpoint
|
|
69
|
+
client.my_endpoints.delete(endpoint_id=endpoint.id)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Browsing the Hub
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# Browse public endpoints
|
|
76
|
+
for endpoint in client.hub.browse():
|
|
77
|
+
print(f"{endpoint.path}: {endpoint.name}")
|
|
78
|
+
|
|
79
|
+
# Get trending endpoints
|
|
80
|
+
for endpoint in client.hub.trending(min_stars=10):
|
|
81
|
+
print(f"{endpoint.name} - {endpoint.stars_count} stars")
|
|
82
|
+
|
|
83
|
+
# Get a specific endpoint by path
|
|
84
|
+
endpoint = client.hub.get("alice/cool-api")
|
|
85
|
+
print(endpoint.readme)
|
|
86
|
+
|
|
87
|
+
# Star/unstar endpoints (requires auth)
|
|
88
|
+
client.hub.star("alice/cool-api")
|
|
89
|
+
client.hub.unstar("alice/cool-api")
|
|
90
|
+
|
|
91
|
+
# Check if you've starred an endpoint
|
|
92
|
+
if client.hub.is_starred("alice/cool-api"):
|
|
93
|
+
print("You've starred this!")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## User Profile
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# Update profile
|
|
100
|
+
user = client.users.update(
|
|
101
|
+
full_name="John D.",
|
|
102
|
+
avatar_url="https://example.com/avatar.png"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Check username availability
|
|
106
|
+
if client.users.check_username("newusername"):
|
|
107
|
+
print("Username is available!")
|
|
108
|
+
|
|
109
|
+
# Change password
|
|
110
|
+
client.auth.change_password(
|
|
111
|
+
current_password="old123",
|
|
112
|
+
new_password="new456"
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Accounting
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Get account balance
|
|
120
|
+
balance = client.accounting.balance()
|
|
121
|
+
print(f"Credits: {balance.credits} {balance.currency}")
|
|
122
|
+
|
|
123
|
+
# List transactions
|
|
124
|
+
for tx in client.accounting.transactions():
|
|
125
|
+
print(f"{tx.created_at}: {tx.amount} - {tx.description}")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Token Persistence
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# Get tokens for saving
|
|
132
|
+
tokens = client.get_tokens()
|
|
133
|
+
if tokens:
|
|
134
|
+
# Save to file, database, etc.
|
|
135
|
+
save_tokens(tokens.access_token, tokens.refresh_token)
|
|
136
|
+
|
|
137
|
+
# Later, restore session
|
|
138
|
+
from syfthub_sdk import AuthTokens
|
|
139
|
+
|
|
140
|
+
tokens = AuthTokens(
|
|
141
|
+
access_token=load_access_token(),
|
|
142
|
+
refresh_token=load_refresh_token()
|
|
143
|
+
)
|
|
144
|
+
client.set_tokens(tokens)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Environment Variables
|
|
148
|
+
|
|
149
|
+
| Variable | Description |
|
|
150
|
+
|----------|-------------|
|
|
151
|
+
| `SYFTHUB_URL` | SyftHub API base URL |
|
|
152
|
+
| `SYFTHUB_ACCOUNTING_URL` | Accounting service URL |
|
|
153
|
+
| `SYFTHUB_ACCOUNTING_EMAIL` | Accounting auth email |
|
|
154
|
+
| `SYFTHUB_ACCOUNTING_PASSWORD` | Accounting auth password |
|
|
155
|
+
|
|
156
|
+
## Error Handling
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from syfthub_sdk import (
|
|
160
|
+
SyftHubError,
|
|
161
|
+
AuthenticationError,
|
|
162
|
+
AuthorizationError,
|
|
163
|
+
NotFoundError,
|
|
164
|
+
ValidationError,
|
|
165
|
+
ConfigurationError,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
client.auth.login(username="john", password="wrong")
|
|
170
|
+
except AuthenticationError as e:
|
|
171
|
+
print(f"Login failed: {e}")
|
|
172
|
+
except SyftHubError as e:
|
|
173
|
+
print(f"API error [{e.status_code}]: {e.message}")
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Context Manager
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
with SyftHubClient(base_url="https://hub.syft.com") as client:
|
|
180
|
+
client.auth.login(username="john", password="secret123")
|
|
181
|
+
# ... do work ...
|
|
182
|
+
# Client is automatically closed
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Pagination
|
|
186
|
+
|
|
187
|
+
All list methods return a `PageIterator` for lazy pagination:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
# Iterate through all items (fetches pages as needed)
|
|
191
|
+
for endpoint in client.my_endpoints.list():
|
|
192
|
+
print(endpoint.name)
|
|
193
|
+
|
|
194
|
+
# Get just the first page
|
|
195
|
+
first_page = client.my_endpoints.list().first_page()
|
|
196
|
+
|
|
197
|
+
# Get all items as a list
|
|
198
|
+
all_items = client.my_endpoints.list().all()
|
|
199
|
+
|
|
200
|
+
# Get first N items
|
|
201
|
+
top_10 = client.my_endpoints.list().take(10)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT
|