Google Cloud Datastore REST Client (Async)
gcloud-rest-datastore is an asynchronous Python client for interacting with Google Cloud Datastore via its REST API. It is part of the `gcloud-aio` monorepo, which provides async clients for various Google Cloud services. The current version is 9.1.0, and the project releases updates to individual service clients as needed, often with shared core dependencies.
Common errors
-
ModuleNotFoundError: No module named 'gcloud_rest_datastore'
cause The `gcloud-rest-datastore` package is not installed in your Python environment.fixRun `pip install gcloud-rest-datastore` to install the library. -
TypeError: object async_generator object at 0x... is not awaitable
cause You attempted to call an async method without `await`, or tried to iterate over an async generator synchronously.fixPrepend `await` to your async function calls (e.g., `await client.lookup(...)`). If dealing with async generators, use `async for`. -
gcloud_rest.auth.exceptions.AuthError: Could not retrieve credentials.
cause The client could not find valid Google Cloud credentials in the environment.fixEnsure `GOOGLE_APPLICATION_CREDENTIALS` points to a valid service account key file, or that your execution environment (e.g., GCP VM, Cloud Run, GKE pod) has a service account with the necessary permissions (e.g., `Datastore User` or `Datastore Editor`). -
RuntimeError: Event loop is already running
cause You are trying to call `asyncio.run()` in an environment where an event loop is already active (e.g., Jupyter Notebook, IPython, or a nested `asyncio.run()` call).fixIn interactive environments, use `nest_asyncio` (e.g., `import nest_asyncio; nest_asyncio.apply()`) or run coroutines directly with `await` if already in an async context. Avoid nesting `asyncio.run()` calls in applications.
Warnings
- gotcha Python 3.9 Compatibility for `gcloud-rest-auth`. While `gcloud-rest-datastore` v9.1.0's PyPI metadata states `requires_python>=3.9`, its dependency `gcloud-rest-auth` v5.4.4 (and newer) explicitly dropped support for Python 3.9. Installing `gcloud-rest-datastore` on Python 3.9 might pull a problematic version of `gcloud-rest-auth`.
- gotcha Asynchronous API Calls. This library is fully asynchronous. All methods that interact with the Datastore API are `awaitable` coroutines. Forgetting to use `await` will result in coroutine objects being returned instead of the actual results, leading to `TypeError` or unexpected behavior.
- gotcha Authentication Setup. The client relies on `google-auth` for authentication, which defaults to `GOOGLE_APPLICATION_CREDENTIALS`, GKE service accounts, or instance metadata. If your environment is not correctly configured for GCP authentication, API calls will fail.
Install
-
pip install gcloud-rest-datastore
Imports
- DatastoreClient
from gcloud_rest_datastore.client import DatastoreClient
from gcloud_rest_datastore import DatastoreClient
- Key
from gcloud_rest_datastore.entities import Key
- Entity
from gcloud_rest_datastore.entities import Entity
- Query
from gcloud_rest_datastore.query import Query
Quickstart
import asyncio
import os
from gcloud_rest_datastore import DatastoreClient
from gcloud_rest_datastore.entities import Key, PathElement, Entity, Property
async def main():
project_id = os.environ.get('GOOGLE_CLOUD_PROJECT', 'your-project-id')
if project_id == 'your-project-id':
print("Please set GOOGLE_CLOUD_PROJECT environment variable or replace 'your-project-id' with your actual project ID.")
return
client = DatastoreClient(project=project_id)
# Create a key
key = Key(project_id=project_id, path=[PathElement(kind='Task', name='sample-task')])
# Create an entity
entity = Entity(
key=key,
properties={
'description': Property(string_value='Learn gcloud-rest-datastore'),
'done': Property(boolean_value=False)
}
)
# Insert/Update the entity
try:
await client.commit(mode='NON_TRANSACTIONAL', mutations=[{'insertOrUpdate': entity}])
print(f"Entity inserted/updated: {key.path[0].name}")
# Lookup the entity
results = await client.lookup(keys=[key])
if results.found:
retrieved_entity = results.found[0].entity
print(f"Retrieved entity: {retrieved_entity.properties['description'].string_value}, Done: {retrieved_entity.properties['done'].boolean_value}")
else:
print("Entity not found.")
except Exception as e:
print(f"An error occurred: {e}")
finally:
await client.close()
if __name__ == '__main__':
asyncio.run(main())