Python
gel-python is the official Gel driver for Python. It provides both blocking IO and asyncio implementations.
Installation
Install the client package from PyPI using your package manager of choice.
$
pip install gel
$
uv add gel
Basic Usage
To start using Gel in Python, create an gel.Client
instance using gel.create_client()
or gel.create_async_client()
for AsyncIO. This client instance manages a pool of connections to the database which it discovers automatically from either being in a gel project init
directory or being provided connection details via Environment Variables. See the environment section of the connection reference for more details and options.
If you're using Gel Cloud to host your development instance, you can use the gel cloud login
command to authenticate with Gel Cloud and then use the gel project init --server-instance <instance-name>
command to create a local project-linked instance that is linked to an Gel Cloud instance. For more details, see the Gel Cloud guide.
import datetime
import gel
client = gel.create_client()
client.query("""
INSERT User {
name := <str>$name,
dob := <cal::local_date>$dob
}
""", name="Bob", dob=datetime.date(1984, 3, 1))
user_set = client.query(
"SELECT User {name, dob} FILTER .name = <str>$name", name="Bob")
# *user_set* now contains
# Set{Object{name := 'Bob', dob := datetime.date(1984, 3, 1)}}
client.close()
import asyncio
import datetime
import gel
client = gel.create_async_client()
async def main():
await client.query("""
INSERT User {
name := <str>$name,
dob := <cal::local_date>$dob
}
""", name="Bob", dob=datetime.date(1984, 3, 1))
user_set = await client.query(
"SELECT User {name, dob} FILTER .name = <str>$name", name="Bob")
# *user_set* now contains
# Set{Object{name := 'Bob', dob := datetime.date(1984, 3, 1)}}
await client.aclose()
asyncio.run(main())
Client connection pools
For server-type applications that handle frequent requests and need the database connection for a short period of time while handling a request, you will want to use a connection pool. Both gel.Client
and gel.AsyncIOClient
come with such a pool.
For gel.Client
, all methods are thread-safe. You can share the same client instance safely across multiple threads, and run queries concurrently. Likewise, AsyncIOClient
is designed to be shared among different asyncio.Task
/coroutines for concurrency.
Below is an example of a web API server running fastapi:
import asyncio
import gel
from fastapi import FastAPI, Query
app = FastAPI()
@app.on_event("startup")
async def startup_event():
"""Initialize the database client on startup."""
app.state.client = gel.create_async_client()
# Optional: explicitly start up the connection pool
await app.state.client.ensure_connected()
@app.get("/users")
async def handle(
name: str = Query(None)
):
"""Handle incoming requests."""
client = app.state.client
# Execute the query on any pool connection
if name:
result = await client.query_single(
'''
SELECT User {first_name, email, bio}
FILTER .name = <str>$username
''', username=name)
else:
result = await client.query(
'''
SELECT User {first_name, email, bio}
''')
return result
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Note that the client instance itself is created synchronously. Pool connections are created lazily as they are needed. If you want to explicitly connect to the database in startup_event()
, use the ensure_connected()
method on the client.
For more information, see API documentation of the blocking client and the asynchronous client.
Transactions
To create a transaction use the transaction()
method on the client instance:
Example:
for tx in client.transaction():
with tx:
tx.execute("INSERT User {name := 'Don'}")
async for tx in client.transaction():
async with tx:
await tx.execute("INSERT User {name := 'Don'}")
When not in an explicit transaction block, any changes to the database will be applied immediately.
For more information, see API documentation of transactions for the blocking client and the AsyncIO client.
Code generation
The gel-python
package exposes a command-line tool to generate typesafe functions from *.edgeql
files, using dataclasses
for objects primarily.
with
name := <str>$name,
select User { first_name, email, bio }
filter .name = name;
$
gel-py
# or
$
python -m gel.codegen
import gel
from .queries import get_user_by_name_sync_edgeql as get_user_by_name_qry
client = gel.create_async_client()
async def main():
result = await get_user_by_name_qry.get_user_by_name(client, name="John")
print(result)
asyncio.run(main())