Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Virtual environments
.venv/
venv/
env/

# Python bytecode
__pycache__/
*.py[cod]

# Packaging / build artifacts
build/
dist/
*.egg-info/
.eggs/

# Test and tooling caches
.pytest_cache/
.mypy_cache/
.ruff_cache/
.coverage
htmlcov/

# Editor and OS files
.idea/
.vscode/
.DS_Store
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

* Breaking: `tables_db`, `documents_db` and `vectors_db` `create` and `update` take `description` before `specification`
* Breaking: `functions.update` takes `description` before `email_enabled`
* Breaking: every service method is now a coroutine and must be awaited; `Client.call` and `Client.chunked_upload` are async as well
* Breaking: the SDK now requires Python 3.11 or later
* Breaking: `requests` was replaced by `httpx2`, changing the transport and connection pooling behaviour
* Breaking: `on_progress` callbacks may now be coroutine functions and are awaited when they are
* Added: `create_query` on `databases`, `documents_db` and `tables_db` to send list queries in the request body
* Added: `account.list_memberships`
* Added: `Client.aclose()` and async context manager support for `Client`
* Added: optional `description` on create and update for databases, collections, tables, attributes, columns, indexes, buckets, functions, sites, variables, topics, webhooks and keys
* Added: `description` on the matching models
* Added: `total` on list methods in `activities`, `backups`, `domains`, `mongo`, `mysql` and `postgresql`
Expand Down
113 changes: 79 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Appwrite is an open-source backend as a service server that abstracts and simpli

## Installation

Requires Python 3.9 or later. Install the [`appwrite`](https://pypi.org/project/appwrite/) package from PyPI:
Requires Python 3.11 or later. Install the [`appwrite`](https://pypi.org/project/appwrite/) package from PyPI:

```bash
pip install appwrite
Expand All @@ -27,6 +27,8 @@ uv add appwrite

## Getting started

Every API call is asynchronous, so every service method returns a coroutine you `await`.

### Initialize the client

Create a client with your Appwrite endpoint, project ID and an [API key](https://appwrite.io/docs/partners/project/api-keys). Find the endpoint and project ID in your project's **Settings** page, and create an API key with only the scopes you need under **API keys** in the project sidebar.
Expand All @@ -44,24 +46,31 @@ API keys grant server-level access to your project. Keep them out of client-side

### Make a request

Create a service object with the client and call any of its methods. Every method returns a typed Pydantic model, so response fields are available as attributes.
Create a service object with the client and await any of its methods. Every method returns a typed Pydantic model, so response fields are available as attributes.

```python
import asyncio

from appwrite.id import ID
from appwrite.services.users import Users

users = Users(client)

user = users.create(
user_id=ID.unique(),
email='email@example.com',
password='password',
name="Walter O'Brien",
)
async def main():
users = Users(client)

user = await users.create(
user_id=ID.unique(),
email='email@example.com',
password='password',
name="Walter O'Brien",
)

print(user.id)
print(user.name)
print(user.to_dict())

print(user.id)
print(user.name)
print(user.to_dict())

asyncio.run(main())
```

See the [API reference](https://appwrite.io/docs/references/cloud/server-python/users) for every service and method.
Expand All @@ -71,6 +80,7 @@ See the [API reference](https://appwrite.io/docs/references/cloud/server-python/
Use `TablesDB` to read and write rows. Pass a Pydantic model as `model_type` to get typed row data back; without it, `row.data` is a `dict`.

```python
import asyncio
from typing import Optional

from pydantic import BaseModel
Expand All @@ -86,41 +96,76 @@ class Post(BaseModel):
excerpt: Optional[str] = None


tables_db = TablesDB(client)
async def main():
tables_db = TablesDB(client)

row = tables_db.create_row(
database_id='<DATABASE_ID>',
table_id='<TABLE_ID>',
row_id=ID.unique(),
data={'title': 'Hello, world', 'published': True},
model_type=Post,
)
row = await tables_db.create_row(
database_id='<DATABASE_ID>',
table_id='<TABLE_ID>',
row_id=ID.unique(),
data={'title': 'Hello, world', 'published': True},
model_type=Post,
)

print(row.id)
print(row.data.title)
print(row.id)
print(row.data.title)

result = tables_db.list_rows(
database_id='<DATABASE_ID>',
table_id='<TABLE_ID>',
queries=[Query.equal('published', True), Query.limit(25)],
model_type=Post,
)
result = await tables_db.list_rows(
database_id='<DATABASE_ID>',
table_id='<TABLE_ID>',
queries=[Query.equal('published', True), Query.limit(25)],
model_type=Post,
)

for row in result.rows:
print(row.data.title)
for row in result.rows:
print(row.data.title)


asyncio.run(main())
```

### Handle errors

Failed requests raise `AppwriteException`, which carries `message`, `code`, `type` and `response`.

```python
import asyncio

from appwrite.exception import AppwriteException

try:
user = users.get(user_id='<USER_ID>')
except AppwriteException as error:
print(error.code, error.type, error.message)

async def main():
try:
user = await users.get(user_id='<USER_ID>')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error example references an out-of-scope variable

In the preceding request example, users is created inside main(), so it is not visible to this separate main; running this error-handling block raises NameError before making a request. Create a Users(client) instance in this example or define it in a shared scope.

Prompt To Fix With AI
This is a comment left during a code review.
Path: README.md
Line: 139

Comment:
**The error example references an out-of-scope variable**

In the preceding request example, `users` is created inside `main()`, so it is not visible to this separate `main`; running this error-handling block raises `NameError` before making a request. Create a `Users(client)` instance in this example or define it in a shared scope.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

🟡 Minor · documentation · Reply if this doesn't apply.

except AppwriteException as error:
print(error.code, error.type, error.message)


asyncio.run(main())
```

### Close the client

The client keeps a pooled HTTP connection open. Close it when you are done, or use it as an async context manager.

```python
async def main():
await client.aclose()


asyncio.run(main())
```

```python
from appwrite.client import Client


async def main():
async with Client() as client:
...


asyncio.run(main())
```

### Self-hosted Appwrite
Expand Down
Loading
Loading