Skip to content
Merged
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
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## 15.0.0

* Add array-based enum parameters (e.g., `permissions: list[BrowserPermission]`).
* Breaking change: `Output` enum has been removed; use `ImageFormat` instead.
* Add `getQueueAudits` support to `Health` service.
* Add longtext/mediumtext/text/varchar attribute and column helpers to `Databases` and `TablesDB` services.

## 14.1.0

* Added ability to create columns and indexes synchronously while creating a table
Expand Down Expand Up @@ -62,4 +69,4 @@

## 9.0.3

* Update sdk to use Numpy-style docstrings
* Update sdk to use Numpy-style docstrings
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2025 Appwrite (https://appwrite.io) and individual contributors.
Copyright (c) 2026 Appwrite (https://appwrite.io) and individual contributors.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Appwrite Python SDK

![License](https://img.shields.io/github/license/appwrite/sdk-for-python.svg?style=flat-square)
![Version](https://img.shields.io/badge/api%20version-1.8.0-blue.svg?style=flat-square)
![Version](https://img.shields.io/badge/api%20version-1.8.1-blue.svg?style=flat-square)
[![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator)
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)

**This SDK is compatible with Appwrite server version 1.8.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-python/releases).**

Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Python SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)
Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Python SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)

![Appwrite](https://github.com/appwrite/appwrite/raw/main/public/images/github.png)

Expand Down
4 changes: 2 additions & 2 deletions appwrite/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ def __init__(self):
self._endpoint = 'https://cloud.appwrite.io/v1'
self._global_headers = {
'content-type': '',
'user-agent' : f'AppwritePythonSDK/14.1.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})',
'user-agent' : f'AppwritePythonSDK/15.0.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})',
'x-sdk-name': 'Python',
'x-sdk-platform': 'server',
'x-sdk-language': 'python',
'x-sdk-version': '14.1.0',
'x-sdk-version': '15.0.0',
'X-Appwrite-Response-Format' : '1.8.0',
}

Expand Down
20 changes: 16 additions & 4 deletions appwrite/encoders/value_class_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
from ..enums.flag import Flag
from ..enums.theme import Theme
from ..enums.timezone import Timezone
from ..enums.output import Output
from ..enums.browser_permission import BrowserPermission
from ..enums.image_format import ImageFormat
from ..enums.relationship_type import RelationshipType
from ..enums.relation_mutate import RelationMutate
from ..enums.index_type import IndexType
from ..enums.order_by import OrderBy
from ..enums.runtime import Runtime
from ..enums.scopes import Scopes
from ..enums.template_reference_type import TemplateReferenceType
from ..enums.vcs_reference_type import VCSReferenceType
from ..enums.deployment_download_type import DeploymentDownloadType
Expand All @@ -24,7 +27,7 @@
from ..enums.adapter import Adapter
from ..enums.compression import Compression
from ..enums.image_gravity import ImageGravity
from ..enums.image_format import ImageFormat
from ..enums.roles import Roles
from ..enums.password_hash import PasswordHash
from ..enums.messaging_provider_type import MessagingProviderType
from ..enums.database_type import DatabaseType
Expand Down Expand Up @@ -64,7 +67,10 @@ def default(self, o):
if isinstance(o, Timezone):
return o.value

if isinstance(o, Output):
if isinstance(o, BrowserPermission):
return o.value

if isinstance(o, ImageFormat):
return o.value

if isinstance(o, RelationshipType):
Expand All @@ -76,9 +82,15 @@ def default(self, o):
if isinstance(o, IndexType):
return o.value

if isinstance(o, OrderBy):
return o.value

if isinstance(o, Runtime):
return o.value

if isinstance(o, Scopes):
return o.value

if isinstance(o, TemplateReferenceType):
return o.value

Expand Down Expand Up @@ -115,7 +127,7 @@ def default(self, o):
if isinstance(o, ImageGravity):
return o.value

if isinstance(o, ImageFormat):
if isinstance(o, Roles):
return o.value

if isinstance(o, PasswordHash):
Expand Down
23 changes: 23 additions & 0 deletions appwrite/enums/browser_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from enum import Enum

class BrowserPermission(Enum):
GEOLOCATION = "geolocation"
CAMERA = "camera"
MICROPHONE = "microphone"
NOTIFICATIONS = "notifications"
MIDI = "midi"
PUSH = "push"
CLIPBOARD_READ = "clipboard-read"
CLIPBOARD_WRITE = "clipboard-write"
PAYMENT_HANDLER = "payment-handler"
USB = "usb"
BLUETOOTH = "bluetooth"
ACCELEROMETER = "accelerometer"
GYROSCOPE = "gyroscope"
MAGNETOMETER = "magnetometer"
AMBIENT_LIGHT_SENSOR = "ambient-light-sensor"
BACKGROUND_SYNC = "background-sync"
PERSISTENT_STORAGE = "persistent-storage"
SCREEN_WAKE_LOCK = "screen-wake-lock"
WEB_SHARE = "web-share"
XR_SPATIAL_TRACKING = "xr-spatial-tracking"
1 change: 1 addition & 0 deletions appwrite/enums/deployment_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ class DeploymentStatus(Enum):
PROCESSING = "processing"
BUILDING = "building"
READY = "ready"
CANCELED = "canceled"
FAILED = "failed"
1 change: 1 addition & 0 deletions appwrite/enums/name.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ class Name(Enum):
V1_WEBHOOKS = "v1-webhooks"
V1_CERTIFICATES = "v1-certificates"
V1_BUILDS = "v1-builds"
V1_SCREENSHOTS = "v1-screenshots"
V1_MESSAGING = "v1-messaging"
V1_MIGRATIONS = "v1-migrations"
1 change: 0 additions & 1 deletion appwrite/enums/o_auth_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,3 @@ class OAuthProvider(Enum):
YANDEX = "yandex"
ZOHO = "zoho"
ZOOM = "zoom"
MOCK = "mock"
5 changes: 5 additions & 0 deletions appwrite/enums/order_by.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from enum import Enum

class OrderBy(Enum):
ASC = "asc"
DESC = "desc"
10 changes: 0 additions & 10 deletions appwrite/enums/output.py

This file was deleted.

6 changes: 6 additions & 0 deletions appwrite/enums/roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from enum import Enum

class Roles(Enum):
ADMIN = "admin"
DEVELOPER = "developer"
OWNER = "owner"
58 changes: 58 additions & 0 deletions appwrite/enums/scopes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from enum import Enum

class Scopes(Enum):
SESSIONS_WRITE = "sessions.write"
USERS_READ = "users.read"
USERS_WRITE = "users.write"
TEAMS_READ = "teams.read"
TEAMS_WRITE = "teams.write"
DATABASES_READ = "databases.read"
DATABASES_WRITE = "databases.write"
COLLECTIONS_READ = "collections.read"
COLLECTIONS_WRITE = "collections.write"
TABLES_READ = "tables.read"
TABLES_WRITE = "tables.write"
ATTRIBUTES_READ = "attributes.read"
ATTRIBUTES_WRITE = "attributes.write"
COLUMNS_READ = "columns.read"
COLUMNS_WRITE = "columns.write"
INDEXES_READ = "indexes.read"
INDEXES_WRITE = "indexes.write"
DOCUMENTS_READ = "documents.read"
DOCUMENTS_WRITE = "documents.write"
ROWS_READ = "rows.read"
ROWS_WRITE = "rows.write"
FILES_READ = "files.read"
FILES_WRITE = "files.write"
BUCKETS_READ = "buckets.read"
BUCKETS_WRITE = "buckets.write"
FUNCTIONS_READ = "functions.read"
FUNCTIONS_WRITE = "functions.write"
SITES_READ = "sites.read"
SITES_WRITE = "sites.write"
LOG_READ = "log.read"
LOG_WRITE = "log.write"
EXECUTION_READ = "execution.read"
EXECUTION_WRITE = "execution.write"
LOCALE_READ = "locale.read"
AVATARS_READ = "avatars.read"
HEALTH_READ = "health.read"
PROVIDERS_READ = "providers.read"
PROVIDERS_WRITE = "providers.write"
MESSAGES_READ = "messages.read"
MESSAGES_WRITE = "messages.write"
TOPICS_READ = "topics.read"
TOPICS_WRITE = "topics.write"
SUBSCRIBERS_READ = "subscribers.read"
SUBSCRIBERS_WRITE = "subscribers.write"
TARGETS_READ = "targets.read"
TARGETS_WRITE = "targets.write"
RULES_READ = "rules.read"
RULES_WRITE = "rules.write"
MIGRATIONS_READ = "migrations.read"
MIGRATIONS_WRITE = "migrations.write"
VCS_READ = "vcs.read"
VCS_WRITE = "vcs.write"
ASSISTANT_READ = "assistant.read"
TOKENS_READ = "tokens.read"
TOKENS_WRITE = "tokens.write"
2 changes: 0 additions & 2 deletions appwrite/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import math
from enum import Enum


class Condition(Enum):
EQUAL = "equal"
NOT_EQUAL = "notEqual"
Expand All @@ -14,7 +13,6 @@ class Condition(Enum):
IS_NULL = "isNull"
IS_NOT_NULL = "isNotNull"


class Operator():
def __init__(self, method, values=None):
self.method = method
Expand Down
55 changes: 54 additions & 1 deletion appwrite/query.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import json


# Inherit from dict to allow for easy serialization
class Query():
def __init__(self, method, attribute=None, values=None):
Expand All @@ -27,6 +26,20 @@ def equal(attribute, value):
def not_equal(attribute, value):
return str(Query("notEqual", attribute, value))

@staticmethod
def regex(attribute, pattern):
"""
Filter resources where attribute matches a regular expression pattern.

Args:
attribute: The attribute to filter on.
pattern: The regular expression pattern to match.

Returns:
The query string.
"""
return str(Query("regex", attribute, pattern))

@staticmethod
def less_than(attribute, value):
return str(Query("lessThan", attribute, value))
Expand All @@ -51,6 +64,32 @@ def is_null(attribute):
def is_not_null(attribute):
return str(Query("isNotNull", attribute, None))

@staticmethod
def exists(attributes):
"""
Filter resources where the specified attributes exist.

Args:
attributes: The list of attributes that must exist.

Returns:
The query string.
"""
return str(Query("exists", None, attributes))

@staticmethod
def not_exists(attributes):
"""
Filter resources where the specified attributes do not exist.

Args:
attributes: The list of attributes that must not exist.

Returns:
The query string.
"""
return str(Query("notExists", None, attributes))

@staticmethod
def between(attribute, start, end):
return str(Query("between", attribute, [start, end]))
Expand Down Expand Up @@ -155,6 +194,20 @@ def or_queries(queries):
def and_queries(queries):
return str(Query("and", None, [json.loads(query) for query in queries]))

@staticmethod
def elem_match(attribute, queries):
"""
Filter array elements where at least one element matches all the specified queries.

Args:
attribute: The attribute containing the array to filter on.
queries: The list of query strings to match against array elements.

Returns:
The query string.
"""
return str(Query("elemMatch", attribute, [json.loads(query) for query in queries]))

@staticmethod
def distance_equal(attribute, values, distance, meters=True):
return str(Query("distanceEqual", attribute, [[values, distance, meters]]))
Expand Down
1 change: 0 additions & 1 deletion appwrite/service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from .client import Client


class Service:
def __init__(self, client: Client):
self.client = client
10 changes: 9 additions & 1 deletion appwrite/services/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,15 @@ def delete_identity(self, identity_id: str) -> Dict[str, Any]:
'content-type': 'application/json',
}, api_params)

def create_jwt(self) -> Dict[str, Any]:
def create_jwt(self, duration: Optional[float] = None) -> Dict[str, Any]:
"""
Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.

Parameters
----------
duration : Optional[float]
Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.

Returns
-------
Dict[str, Any]
Expand All @@ -203,6 +208,9 @@ def create_jwt(self) -> Dict[str, Any]:
api_path = '/account/jwts'
api_params = {}

if duration is not None:
api_params['duration'] = duration

return self.client.call('post', api_path, {
'content-type': 'application/json',
}, api_params)
Expand Down
Loading