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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Change Log

## 24.0.0rc1

* Breaking: `Execution.functionId` is replaced by `resourceId` and `resourceType`, now that executions cover both functions and sites
* Breaking: `AppInstallation.authorizationDetails` is now an array instead of an object
* Breaking: removed `dedicatedDatabases.execute` from `ProjectKeyScopes`
* Breaking: `EmbeddingModel` no longer offers `embedding-gemma` or `bge-small`
* Added: `documentsDB`, `vectorsDB`, `mysql`, `postgresql`, and `mongo` services, no longer hidden from server SDKs
* Added: `DocumentsDBIndexType` and `VectorsDBIndexType` enums
* Added: dedicated database models for branches, backups, restorations, poolers, PITR windows, extensions, and executions
* Added: `PostgresExtension`, `VectorsdbCollection`, `AttributeObject`, and `AttributeVector` models
* Added: `ExecutionResourceType` enum and `resourceType` on the `Execution` model
* Added: `OAuth2HuggingFace` model and the `huggingface` OAuth provider
* Added: `userId`, `emailHash`, and `name` parameters to `avatars.getPhoto`
* Added: `error`, `containerStatus`, and `lifecycleState` on the `Database` model
* Added: `changelogWatermark` on the `DatabaseMigration` model
* Added: `total` on the `DedicatedDatabaseBranchList` model
* Updated: `DedicatedDatabaseOperation.status` documents the new `queued` state

## 23.0.0

* Breaking: removed `account.createJWT`; use `users.createJWT` instead. A leaked JWT could mint further JWTs, letting a credential outlive its own expiry — a session cannot duplicate itself to live forever either
Expand Down
1 change: 0 additions & 1 deletion appwrite/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

93 changes: 49 additions & 44 deletions appwrite/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@
from .exception import AppwriteException
from .encoders.value_class_encoder import ValueClassEncoder


class Client:
def __init__(self):
self._chunk_size = 5*1024*1024
self._chunk_size = 5 * 1024 * 1024
self._self_signed = False
self._endpoint = 'https://cloud.appwrite.io/v1'
self._global_headers = {
'content-type': '',
'user-agent' : f'AppwritePythonSDK/23.0.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})',
'user-agent': f'AppwritePythonSDK/24.0.0rc1 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})',
'x-sdk-name': 'Python',
'x-sdk-platform': 'server',
'x-sdk-language': 'python',
'x-sdk-version': '23.0.0',
'X-Appwrite-Response-Format' : '1.9.6',
'x-sdk-version': '24.0.0rc1',
'X-Appwrite-Response-Format': '1.9.6',
}
self._config = {}

Expand Down Expand Up @@ -174,7 +175,7 @@ def call(self, method, path='', headers=None, params=None, response_type='json')
files=files,
headers=headers,
verify=(not self._self_signed),
allow_redirects=False if response_type == 'location' else True
allow_redirects=False if response_type == 'location' else True,
)

response.raise_for_status()
Expand All @@ -197,7 +198,9 @@ def call(self, method, path='', headers=None, params=None, response_type='json')
if response != None:
content_type = response.headers['Content-Type']
if content_type.startswith('application/json'):
raise AppwriteException(response.json()['message'], response.status_code, response.json().get('type'), response.text)
raise AppwriteException(
response.json()['message'], response.status_code, response.json().get('type'), response.text
)
else:
raise AppwriteException(response.text, response.status_code, None, response.text)
else:
Expand All @@ -206,11 +209,11 @@ def call(self, method, path='', headers=None, params=None, response_type='json')
def chunked_upload(
self,
path,
headers = None,
params = None,
param_name = '',
on_progress = None,
upload_id = ''
headers=None,
params=None,
param_name='',
on_progress=None,
upload_id='',
):
input_file = params[param_name]

Expand All @@ -227,21 +230,17 @@ def chunked_upload(
input_file.data = input.read()

params[param_name] = input_file
return self.call(
'post',
path,
headers,
params
)
return self.call('post', path, headers, params)

offset = 0
counter = 0

try:
result = self.call('get', path + '/' + upload_id, headers)
counter = result['chunksUploaded']
except:
pass
if upload_id:
try:
result = self.call('get', path + '/' + upload_id, headers)
counter = result['chunksUploaded']
except:
pass

if counter > 0:
offset = counter * self._chunk_size
Expand All @@ -250,11 +249,13 @@ def chunked_upload(
chunks = []
while offset < size:
end = min(offset + self._chunk_size, size)
chunks.append({
'index': counter,
'start': offset,
'end': end,
})
chunks.append(
{
'index': counter,
'start': offset,
'end': end,
}
)
offset = end
counter = counter + 1

Expand Down Expand Up @@ -286,7 +287,7 @@ def upload_chunk(chunk, current_upload_id):
chunk_input = InputFile.from_bytes(
read_chunk(chunk['start'], chunk['end']),
input_file.filename,
getattr(input_file, 'mime_type', None)
getattr(input_file, 'mime_type', None),
)
chunk_params = {**params, param_name: chunk_input}
chunk_headers = {**headers}
Expand All @@ -310,13 +311,15 @@ def upload_chunk(chunk, current_upload_id):
uploaded_size = chunks[0]['end']

if on_progress is not None:
on_progress({
"$id": result.get("$id"),
"progress": uploaded_size / size * 100,
"sizeUploaded": uploaded_size,
"chunksTotal": total_chunks,
"chunksUploaded": completed_count,
})
on_progress(
{
"$id": result.get("$id"),
"progress": uploaded_size / size * 100,
"sizeUploaded": uploaded_size,
"chunksTotal": total_chunks,
"chunksUploaded": completed_count,
}
)

def upload_remaining_chunk(chunk):
nonlocal completed_count, uploaded_size, last_result, final_result
Expand All @@ -328,13 +331,15 @@ def upload_remaining_chunk(chunk):
if is_upload_complete(chunk_result):
final_result = chunk_result
if on_progress is not None:
on_progress({
"$id": upload_id_header,
"progress": uploaded_size / size * 100,
"sizeUploaded": uploaded_size,
"chunksTotal": total_chunks,
"chunksUploaded": completed_count,
})
on_progress(
{
"$id": upload_id_header,
"progress": uploaded_size / size * 100,
"sizeUploaded": uploaded_size,
"chunksTotal": total_chunks,
"chunksUploaded": completed_count,
}
)

with ThreadPoolExecutor(max_workers=8) as executor:
futures = [executor.submit(upload_remaining_chunk, chunk) for chunk in chunks[1:]]
Expand All @@ -349,8 +354,8 @@ def flatten(self, data, prefix='', stringify=False):

for key in data:
value = data[key] if isinstance(data, dict) else key
finalKey = prefix + '[' + key +']' if prefix else key
finalKey = prefix + '[' + str(i) +']' if isinstance(data, list) else finalKey
finalKey = prefix + '[' + key + ']' if prefix else key
finalKey = prefix + '[' + str(i) + ']' if isinstance(data, list) else finalKey
i += 1

if isinstance(value, list) or isinstance(value, dict):
Expand Down
1 change: 0 additions & 1 deletion appwrite/encoders/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

13 changes: 13 additions & 0 deletions appwrite/encoders/value_class_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from ..enums.relation_mutate import RelationMutate
from ..enums.databases_index_type import DatabasesIndexType
from ..enums.order_by import OrderBy
from ..enums.documents_db_index_type import DocumentsDBIndexType
from ..enums.embedding_model import EmbeddingModel
from ..enums.runtime import Runtime
from ..enums.project_key_scopes import ProjectKeyScopes
Expand Down Expand Up @@ -47,12 +48,14 @@
from ..enums.tables_db_index_type import TablesDBIndexType
from ..enums.password_hash import PasswordHash
from ..enums.messaging_provider_type import MessagingProviderType
from ..enums.vectors_db_index_type import VectorsDBIndexType
from ..enums.database_type import DatabaseType
from ..enums.database_status import DatabaseStatus
from ..enums.attribute_status import AttributeStatus
from ..enums.column_status import ColumnStatus
from ..enums.index_status import IndexStatus
from ..enums.deployment_status import DeploymentStatus
from ..enums.execution_resource_type import ExecutionResourceType
from ..enums.execution_trigger import ExecutionTrigger
from ..enums.execution_status import ExecutionStatus
from ..enums.o_auth2_google_prompt import OAuth2GooglePrompt
Expand All @@ -63,6 +66,7 @@
from ..enums.message_status import MessageStatus
from ..enums.billing_plan_group import BillingPlanGroup


class ValueClassEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, AppwriteModel):
Expand Down Expand Up @@ -113,6 +117,9 @@ def default(self, o):
if isinstance(o, OrderBy):
return o.value

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

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

Expand Down Expand Up @@ -209,6 +216,9 @@ def default(self, o):
if isinstance(o, MessagingProviderType):
return o.value

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

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

Expand All @@ -227,6 +237,9 @@ def default(self, o):
if isinstance(o, DeploymentStatus):
return o.value

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

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

Expand Down
1 change: 0 additions & 1 deletion appwrite/enums/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

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


class Adapter(Enum):
STATIC = "static"
SSR = "ssr"
1 change: 1 addition & 0 deletions appwrite/enums/attribute_status.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class AttributeStatus(Enum):
AVAILABLE = "available"
PROCESSING = "processing"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/authentication_factor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class AuthenticationFactor(Enum):
EMAIL = "email"
PHONE = "phone"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/authenticator_type.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from enum import Enum


class AuthenticatorType(Enum):
TOTP = "totp"
1 change: 1 addition & 0 deletions appwrite/enums/backup_services.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class BackupServices(Enum):
DATABASES = "databases"
TABLESDB = "tablesdb"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/billing_plan_group.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class BillingPlanGroup(Enum):
STARTER = "starter"
PRO = "pro"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/browser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class Browser(Enum):
AVANT_BROWSER = "aa"
ANDROID_WEBVIEW_BETA = "an"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/browser_permission.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class BrowserPermission(Enum):
GEOLOCATION = "geolocation"
CAMERA = "camera"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/browser_theme.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class BrowserTheme(Enum):
LIGHT = "light"
DARK = "dark"
2 changes: 2 additions & 0 deletions appwrite/enums/build_runtime.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class BuildRuntime(Enum):
NODE_14_5 = "node-14.5"
NODE_16_0 = "node-16.0"
Expand Down Expand Up @@ -79,6 +80,7 @@ class BuildRuntime(Enum):
BUN_1_1 = "bun-1.1"
BUN_1_2 = "bun-1.2"
BUN_1_3 = "bun-1.3"
BUN_1_4 = "bun-1.4"
GO_1_23 = "go-1.23"
GO_1_24 = "go-1.24"
GO_1_25 = "go-1.25"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/column_status.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class ColumnStatus(Enum):
AVAILABLE = "available"
PROCESSING = "processing"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/compression.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class Compression(Enum):
NONE = "none"
GZIP = "gzip"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/credit_card.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class CreditCard(Enum):
AMERICAN_EXPRESS = "amex"
ARGENCARD = "argencard"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/database_status.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class DatabaseStatus(Enum):
PROVISIONING = "provisioning"
READY = "ready"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/database_type.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class DatabaseType(Enum):
LEGACY = "legacy"
TABLESDB = "tablesdb"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/databases_index_type.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class DatabasesIndexType(Enum):
KEY = "key"
FULLTEXT = "fulltext"
Expand Down
1 change: 1 addition & 0 deletions appwrite/enums/deployment_download_type.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class DeploymentDownloadType(Enum):
SOURCE = "source"
OUTPUT = "output"
Loading