API Reference
read_only

dbzero.read_only()

dbzero-procommercial edition

with dbzero.read_only():

The read_only() context manager protects a code block that is known and expected to be non-mutating. It lets reads proceed, but rejects dbzero durable mutations immediately so accidental writes are caught close to the source.

Use it around validation, authorization checks, query handlers, report generation, dry-run logic, and other code paths that should only inspect dbzero state.


Parameters

This method takes no parameters.


Yields

The context manager does not yield a required value.


Side Effects

  • Allows Reads: Reading fields, running queries, and fetching existing objects are allowed.
  • Rejects Mutations: Memo field assignment, collection mutation, tag changes, index updates, dbzero.touch(), and durable object creation raise RuntimeError.
  • Protects the Current Context: The guard applies to dbzero durable mutations in the current execution context, not just to a single prefix.
  • Nests Safely: Nested read_only() blocks are allowed and restore the previous read-only state when they exit.

Errors

Mutating dbzero operations inside the block raise RuntimeError with a message that identifies read-only mutation protection.


Examples

Protecting Validation Logic

def can_approve(document, user):
    with db0.read_only():
        policy = next(db0.find(ApprovalPolicy, "active"))
        user_roles = list(db0.find(db0.as_tag("ROLE", user)))
 
        return (
            document.status == "pending"
            and policy.minimum_role in user_roles
        )

Rejecting Accidental Writes

document = next(db0.find(Document, "pending"))
 
with db0.read_only():
    assert document.status == "pending"
 
    # Raises RuntimeError.
    document.status = "approved"

Interaction with atomic()

Starting dbzero.atomic() inside read_only() is optimized as a no-op, because a protected non-mutating block cannot validly create atomic changes. Mutation attempts still fail.

with db0.read_only():
    with db0.atomic():
        # Raises RuntimeError.
        order.status = "submitted"

Async Functions

There is no separate async_read_only() API. Use the regular context manager in async functions.

async def render_dashboard(user):
    with db0.read_only():
        widgets = list(db0.find(DashboardWidget, db0.as_tag("OWNER", user)))
        await load_external_metrics()
        return build_dashboard(widgets)
⚠️

Keep a read_only() block active across await only when that is intentional. Child tasks created while the block is active may inherit the protected non-mutating context.