WASM (Pyodide)
WASM (Pyodide)¶
The packages are pure Python wheels, so micropip installs them:
from capo_s3 import AsyncS3Client
async with AsyncS3Client(
region="eu-central-1",
credentials={"access_key": "ASIA...", "secret_key": "...", "session_token": "..."},
) as s3:
await s3.put_object("bucket", "hello.txt", body=b"hi from the browser")
async with s3.get_object("bucket", "hello.txt") as response:
async for chunk in response["body"]:
print(chunk)
In a page:
<script src="https://cdn.jsdelivr.net/pyodide/v314.0.7/full/pyodide.js"></script>
<script type="module">
const pyodide = await loadPyodide();
await pyodide.loadPackage("micropip");
await pyodide.runPythonAsync(`
import micropip
await micropip.install("capo-s3")
from capo_s3 import AsyncS3Client
async with AsyncS3Client(region="eu-central-1", credentials={...}) as s3:
async for bucket in s3.iter_list_buckets():
print(bucket)
`);
</script>
There is no ~/.aws and no metadata service in a browser, so pass credentials= or fetch them from your backend:
from datetime import datetime
from zapros import AsyncClient
from capo_s3 import AsyncS3Client, CachedProvider, Credentials, CredentialsProvider
class BackendCredentials(CredentialsProvider):
def resolve_identity(self) -> Credentials:
raise NotImplementedError("async only")
async def aresolve_identity(self) -> Credentials:
response = await AsyncClient().get("https://api.example.com/aws-credentials")
data = response.json
return {
"access_key": data["access_key"],
"secret_key": data["secret_key"],
"session_token": data["session_token"],
"expiration": datetime.fromisoformat(data["expiration"]),
}
AsyncS3Client(region="eu-central-1", credentials_provider=CachedProvider(BackendCredentials()))
Requests go through the browser's fetch, so the bucket needs a CORS rule for your origin:
await s3.put_bucket_cors(
"bucket",
cors_configuration={
"cors_rules": [
{
"allowed_origins": ["https://app.example.com"],
"allowed_methods": ["GET", "PUT"],
"allowed_headers": ["*"],
"expose_headers": ["ETag"],
}
]
},
)
What is different under Pyodide:
- Only the
Async*clients work;S3Client()raisesRuntimeError. asyncio only, no trio. - The HTTP handler is zapros'
AsyncPyodideHandler, picked automatically. - No threads, so
Body.async_from_pathis unavailable. Passbytes, an async iterator, or aBodywith your own opener. - Node works too; that is how the integration tests run in CI.