riffsdk 0.4.2__tar.gz → 0.4.3__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.
- {riffsdk-0.4.2 → riffsdk-0.4.3}/.github/workflows/release.yml +16 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/CHANGELOG.md +24 -0
- riffsdk-0.4.3/PKG-INFO +127 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/pyproject.toml +8 -1
- riffsdk-0.4.2/PKG-INFO +0 -9
- {riffsdk-0.4.2 → riffsdk-0.4.3}/.github/workflows/ci.yml +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/.github/workflows/pr-comment.yml +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/.gitignore +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/.python-version +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/AGENTS.md +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/CLAUDE.md +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/LICENCE +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/README.md +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/examples/async_client.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/examples/basic_crud.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/examples/file_upload_download.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/examples/optimistic_concurrency.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/mise.toml +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/__init__.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/__main__.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/_cli.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/_internal/__init__.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/_internal/auth.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/_internal/config.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/__init__.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_async_client.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_client.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_http.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_models.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_session.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_streaming.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/_upload.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/exceptions.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/src/riffsdk/storage/py.typed +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/__init__.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_async_client.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_cli.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_client.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_exceptions.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_http.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_imports.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_integration.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_models.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_session.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_streaming.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/tests/test_upload.py +0 -0
- {riffsdk-0.4.2 → riffsdk-0.4.3}/uv.lock +0 -0
|
@@ -86,3 +86,19 @@ jobs:
|
|
|
86
86
|
path: dist/
|
|
87
87
|
- name: Publish to PyPI
|
|
88
88
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
89
|
+
- name: Verify release landed on PyPI
|
|
90
|
+
env:
|
|
91
|
+
TAG: ${{ needs.release.outputs.tag }}
|
|
92
|
+
run: |
|
|
93
|
+
VER="${TAG#v}"
|
|
94
|
+
echo "Verifying riffsdk ${VER} is available on PyPI..."
|
|
95
|
+
for i in $(seq 1 12); do
|
|
96
|
+
if curl -sf "https://pypi.org/pypi/riffsdk/${VER}/json" >/dev/null; then
|
|
97
|
+
echo "riffsdk ${VER} is live on PyPI"
|
|
98
|
+
exit 0
|
|
99
|
+
fi
|
|
100
|
+
echo "not yet on PyPI, retry ${i}/12..."
|
|
101
|
+
sleep 10
|
|
102
|
+
done
|
|
103
|
+
echo "::error::riffsdk ${VER} never appeared on PyPI despite a successful upload step (likely a silent edge 200 — see https://upload.pypi.org/legacy/ response in the publish step)"
|
|
104
|
+
exit 1
|
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v0.4.3 (2026-06-11)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Add project homepage URL ([#12](https://github.com/databutton/riff-sdk-python/pull/12),
|
|
10
|
+
[`7333ba9`](https://github.com/databutton/riff-sdk-python/commit/7333ba9badb64eef3b111b74ee060fb5a6538c5b))
|
|
11
|
+
|
|
12
|
+
- Declare MIT license and package author
|
|
13
|
+
([#12](https://github.com/databutton/riff-sdk-python/pull/12),
|
|
14
|
+
[`7333ba9`](https://github.com/databutton/riff-sdk-python/commit/7333ba9badb64eef3b111b74ee060fb5a6538c5b))
|
|
15
|
+
|
|
16
|
+
- Include README as package long description
|
|
17
|
+
([#12](https://github.com/databutton/riff-sdk-python/pull/12),
|
|
18
|
+
[`7333ba9`](https://github.com/databutton/riff-sdk-python/commit/7333ba9badb64eef3b111b74ee060fb5a6538c5b))
|
|
19
|
+
|
|
20
|
+
- Populate pypi release details and check publishing in CI job
|
|
21
|
+
([#12](https://github.com/databutton/riff-sdk-python/pull/12),
|
|
22
|
+
[`7333ba9`](https://github.com/databutton/riff-sdk-python/commit/7333ba9badb64eef3b111b74ee060fb5a6538c5b))
|
|
23
|
+
|
|
24
|
+
- Verify PyPI publish actually landed before passing release
|
|
25
|
+
([#12](https://github.com/databutton/riff-sdk-python/pull/12),
|
|
26
|
+
[`7333ba9`](https://github.com/databutton/riff-sdk-python/commit/7333ba9badb64eef3b111b74ee060fb5a6538c5b))
|
|
27
|
+
|
|
28
|
+
|
|
5
29
|
## v0.4.2 (2026-06-11)
|
|
6
30
|
|
|
7
31
|
### Bug Fixes
|
riffsdk-0.4.3/PKG-INFO
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: riffsdk
|
|
3
|
+
Version: 0.4.3
|
|
4
|
+
Summary: Python SDK for the Riff Storage API
|
|
5
|
+
Project-URL: Homepage, https://riff.ai
|
|
6
|
+
Author-email: Martin Sandve Alnæs <msa@databutton.io>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENCE
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Requires-Dist: httpx>=0.27
|
|
11
|
+
Requires-Dist: pydantic>=2.6
|
|
12
|
+
Requires-Dist: tenacity>=8.3
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# riffsdk
|
|
16
|
+
|
|
17
|
+
Python SDK for the Riff Storage API. Provides sync and async clients for storing, retrieving, and managing objects.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv add riffsdk
|
|
23
|
+
# or
|
|
24
|
+
pip install riffsdk
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or install from a branch (for pre-release testing):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv add git+https://github.com/databutton/riff-sdk-python.git@main
|
|
31
|
+
# or
|
|
32
|
+
pip install git+https://github.com/databutton/riff-sdk-python.git@main
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from riffsdk.storage import StorageClient
|
|
39
|
+
|
|
40
|
+
client = StorageClient()
|
|
41
|
+
|
|
42
|
+
# Upload
|
|
43
|
+
meta = client.put("hello.txt", "Hello, world!")
|
|
44
|
+
|
|
45
|
+
# Download
|
|
46
|
+
data = client.get("hello.txt")
|
|
47
|
+
|
|
48
|
+
# List
|
|
49
|
+
for obj in client.list("hello"):
|
|
50
|
+
print(f"{obj.key} ({obj.size} bytes)")
|
|
51
|
+
|
|
52
|
+
# Delete
|
|
53
|
+
client.delete("hello.txt")
|
|
54
|
+
|
|
55
|
+
client.close()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Async
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from riffsdk.storage import AsyncStorageClient
|
|
62
|
+
|
|
63
|
+
async with AsyncStorageClient() as client:
|
|
64
|
+
await client.put("key", b"data", content_type="application/octet-stream")
|
|
65
|
+
data = await client.get("key")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Authentication
|
|
69
|
+
|
|
70
|
+
Set the `RIFF_TOKEN` environment variable. The SDK picks it up automatically.
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
### Clients
|
|
75
|
+
|
|
76
|
+
- `StorageClient` -- sync client
|
|
77
|
+
- `AsyncStorageClient` -- async client
|
|
78
|
+
|
|
79
|
+
Both support: `put`, `get`, `stat`, `exists`, `list`, `delete`, `close`, and context manager usage.
|
|
80
|
+
|
|
81
|
+
### Models
|
|
82
|
+
|
|
83
|
+
- `ObjectMeta` -- metadata for a stored object (key, version, size, content_type, timestamps)
|
|
84
|
+
- `UploadResult`, `DownloadResult` -- operation results
|
|
85
|
+
- `ListPage` -- paginated listing
|
|
86
|
+
- `Scope` -- access scope (use `account_scope()`, `project_scope()`, `session_scope()`)
|
|
87
|
+
|
|
88
|
+
### Uploads
|
|
89
|
+
|
|
90
|
+
- `ResumableUpload` / `AsyncResumableUpload` -- multipart resumable uploads for large files
|
|
91
|
+
- `StorageReader` / `StorageWriter` -- streaming read/write
|
|
92
|
+
|
|
93
|
+
### Exceptions
|
|
94
|
+
|
|
95
|
+
All exceptions inherit from `StorageError`:
|
|
96
|
+
|
|
97
|
+
- `AuthorisationError`
|
|
98
|
+
- `ObjectNotFoundError`
|
|
99
|
+
- `VersionConflictError`
|
|
100
|
+
- `AlreadyExistsError`
|
|
101
|
+
- `LeaseConflictError`
|
|
102
|
+
- `UploadNotFoundError`
|
|
103
|
+
- `QuotaExceededError`
|
|
104
|
+
- `PartMismatchError`
|
|
105
|
+
- `StorageTransportError`
|
|
106
|
+
|
|
107
|
+
## Examples
|
|
108
|
+
|
|
109
|
+
See the `examples/` directory for complete working examples:
|
|
110
|
+
|
|
111
|
+
- `basic_crud.py` -- put, get, list, delete
|
|
112
|
+
- `async_client.py` -- async usage with asyncio
|
|
113
|
+
- `file_upload_download.py` -- file uploads with progress
|
|
114
|
+
- `optimistic_concurrency.py` -- version-based conflict handling
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv sync --dev # Install dependencies
|
|
122
|
+
mise run test # Run tests
|
|
123
|
+
mise run lint # Lint
|
|
124
|
+
mise run format # Format code
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
See `AGENTS.md` for full development workflow details.
|
|
@@ -4,11 +4,18 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "riffsdk"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.3"
|
|
8
8
|
description = "Python SDK for the Riff Storage API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENCE"]
|
|
12
|
+
authors = [{ name = "Martin Sandve Alnæs", email = "msa@databutton.io" }]
|
|
9
13
|
requires-python = ">=3.11"
|
|
10
14
|
dependencies = ["httpx>=0.27", "pydantic>=2.6", "tenacity>=8.3"]
|
|
11
15
|
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://riff.ai"
|
|
18
|
+
|
|
12
19
|
[project.scripts]
|
|
13
20
|
riffsdk = "riffsdk._cli:main"
|
|
14
21
|
|
riffsdk-0.4.2/PKG-INFO
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|