Skip to content

Impersonation

Forgejo lets an administrator act as another user by sending a Sudo header naming them. pyfj models this as client-scoped state rather than a per-call argument: the constructor's sudo= sets the default, and the effective value is resolved when each request is sent.

The default and the override

from pyfj import Forgejo

with Forgejo("https://codeberg.org", token="...", sudo="alice") as client:
    client.user.get()  # acts as alice

    client.sudo = "bob"
    client.user.get()  # acts as bob

    client.sudo = None  # clears the override; back to alice

Assigning client.sudo overrides the default for the current context; assigning None clears the override and restores the constructor's default.

Scope an override to a block

sudo_as(...) is a context manager: it applies for the with (or async with) block and restores the previous value on exit, even when the block raises. Scopes nest:

with client.sudo_as("alice"):
    profile = client.user.get()

    with client.sudo_as("bob"):
        client.repos.issues.create("bob", "notes", title="Delegate the review")
    # alice again

Context-local, not global

Overrides live in a ContextVar owned by each client, not in process-global state. Sibling asyncio tasks and threads are unaffected by each other, and tasks created with asyncio.create_task inherit the value that was current at creation time. Pagination reads the effective value on every page fetch, so a scope that changes mid-iteration applies to later pages.

sudo_as accepts async with on either client:

from pyfj import AsyncForgejo

async with AsyncForgejo("https://codeberg.org", token="...") as client:
    async with client.sudo_as("alice"):
        user = await client.user.get()