Skip to content

Entry points

create_quelware_client

create_quelware_client(
    endpoint="localhost",
    port=50051,
    session_agent=None,
    configuration_agent=None,
    health_agent_factory=None,
    resource_agent_factory=None,
    instrument_agent_factory=None,
    diagnostics_agent_factory=None,
    worker_agent_factory=None,
    pat=None,
)

Create a client connected to a QuEL system over gRPC.

Opens a gRPC channel to endpoint:port and builds the default per-unit agents. The returned client should be used as an async context manager so the channel is closed on exit.

Parameters:

Name Type Description Default
endpoint str

Host of the control server.

'localhost'
port int

Port of the control server.

50051
session_agent SessionAgent | None

Override for the session agent. Defaults to a gRPC agent targeting the central server.

None
configuration_agent SystemConfigurationAgent | None

Override for the system-configuration agent. Defaults to a gRPC agent targeting the central server.

None
health_agent_factory AgentFactory[HealthAgent] | None

Override for the per-unit health agent factory. When omitted, health checks run against a default agent.

None
resource_agent_factory AgentFactory[ResourceAgent] | None

Override for the per-unit resource agent factory.

None
instrument_agent_factory AgentFactory[InstrumentAgent] | None

Override for the per-unit instrument agent factory.

None
diagnostics_agent_factory AgentFactory[DiagnosticsAgent] | None

Override for the per-unit diagnostics agent factory.

None
worker_agent_factory AgentFactory[WorkerAgent] | None

Override for the per-unit worker agent factory.

None
pat PatProvider | str | None

Personal Access Token used to authenticate. May be the token string, a callable returning it, or None to load it from the configuration file (~/.config/quelware-client/pat).

None

Returns:

Type Description
QuelwareClient

A configured, not-yet-started QuelwareClient.

Raises:

Type Description
ValueError

If pat is neither a string, a callable, nor None.

Source code in quelware-client/src/quelware_client/client/_grpc.py
def create_quelware_client(  # noqa: PLR0913
    endpoint: str = "localhost",
    port: int = 50051,
    session_agent: SessionAgent | None = None,
    configuration_agent: SystemConfigurationAgent | None = None,
    health_agent_factory: AgentFactory[HealthAgent] | None = None,
    resource_agent_factory: AgentFactory[ResourceAgent] | None = None,
    instrument_agent_factory: AgentFactory[InstrumentAgent] | None = None,
    diagnostics_agent_factory: AgentFactory[DiagnosticsAgent] | None = None,
    worker_agent_factory: AgentFactory[WorkerAgent] | None = None,
    pat: PatProvider | str | None = None,
) -> QuelwareClient:
    """Create a client connected to a QuEL system over gRPC.

    Opens a gRPC channel to ``endpoint:port`` and builds the default per-unit
    agents. The returned client should be used as an async context manager so
    the channel is closed on exit.

    Args:
        endpoint: Host of the control server.
        port: Port of the control server.
        session_agent: Override for the session agent. Defaults to a gRPC
            agent targeting the central server.
        configuration_agent: Override for the system-configuration agent.
            Defaults to a gRPC agent targeting the central server.
        health_agent_factory: Override for the per-unit health agent factory.
            When omitted, health checks run against a default agent.
        resource_agent_factory: Override for the per-unit resource agent
            factory.
        instrument_agent_factory: Override for the per-unit instrument agent
            factory.
        diagnostics_agent_factory: Override for the per-unit diagnostics agent
            factory.
        worker_agent_factory: Override for the per-unit worker agent factory.
        pat: Personal Access Token used to authenticate. May be the token
            string, a callable returning it, or None to load it from the
            configuration file (``~/.config/quelware-client/pat``).

    Returns:
        A configured, not-yet-started `QuelwareClient`.

    Raises:
        ValueError: If ``pat`` is neither a string, a callable, nor None.
    """
    channel = Channel(endpoint, port)

    if pat is None:
        _pat = pat_provider_from_config()
    elif isinstance(pat, str):
        _pat = pat
    elif callable(pat):
        _pat = pat()
    else:
        raise ValueError(f"Unknown type for pat: {pat}")

    if health_agent_factory is None:
        health_agent_factory = _create_default_health_agent_factory(channel, _pat)

    if resource_agent_factory is None:
        resource_agent_factory = _create_default_resource_agent_factory(channel, _pat)

    if instrument_agent_factory is None:
        instrument_agent_factory = _create_default_instrument_agent_factory(
            channel, _pat
        )

    if diagnostics_agent_factory is None:
        diagnostics_agent_factory = _create_default_diagnostics_agent_factory(
            channel, _pat
        )

    if worker_agent_factory is None:
        worker_agent_factory = _create_default_worker_agent_factory(channel)

    central_server_metadata = _CENTRAL_SERVER_METADATA_BASE | {"x-pat": _pat}

    agent_container = AgentContainer()
    if session_agent is None:
        agent_container.session = SessionAgentGrpc(
            channel, metadata=central_server_metadata
        )
    if configuration_agent is None:
        agent_container.system_configuration = SystemConfigurationAgentGrpc(
            channel, metadata=central_server_metadata
        )
    agent_container.trigger = TriggerAgentGrpc(
        channel, metadata=central_server_metadata
    )
    return QuelwareClient(
        agent=agent_container,
        health_agent_factory=health_agent_factory,
        resource_agent_factory=resource_agent_factory,
        instrument_agent_factory=instrument_agent_factory,
        diagnostics_agent_factory=diagnostics_agent_factory,
        worker_agent_factory=worker_agent_factory,
        close_handlers=[channel.close],
    )

create_standalone_client

create_standalone_client(
    endpoint="localhost",
    port=50051,
    unit_label="mock-unit",
    skip_lock_check=True,
    pat=None,
)

Create a client that talks directly to a single worker server.

Intended for testing. The session and system-configuration agents are mocked (a single unit, always ACTIVE), while the resource, instrument, diagnostics, and worker agents connect over gRPC to endpoint:port. The target worker server must be running with lock checking disabled.

Parameters:

Name Type Description Default
endpoint str

Host of the worker server.

'localhost'
port int

Port of the worker server.

50051
unit_label str

Label to assign to the single mocked unit.

'mock-unit'
skip_lock_check bool

When True (the default), sessions skip verifying that their resources are locked.

True
pat PatProvider | str | None

Personal Access Token, as accepted by create_quelware_client().

None

Returns:

Type Description
QuelwareClient

A configured, not-yet-started QuelwareClient.

Raises:

Type Description
ValueError

If pat is neither a string, a callable, nor None.

Source code in quelware-client/src/quelware_client/client/_standalone_grpc.py
def create_standalone_client(
    endpoint: str = "localhost",
    port: int = 50051,
    unit_label: str = "mock-unit",
    skip_lock_check: bool = True,
    pat: PatProvider | str | None = None,
) -> QuelwareClient:
    """Create a client that talks directly to a single worker server.

    Intended for testing. The session and system-configuration agents are
    mocked (a single unit, always ACTIVE), while the resource, instrument,
    diagnostics, and worker agents connect over gRPC to ``endpoint:port``. The
    target worker server must be running with lock checking disabled.

    Args:
        endpoint: Host of the worker server.
        port: Port of the worker server.
        unit_label: Label to assign to the single mocked unit.
        skip_lock_check: When True (the default), sessions skip verifying that
            their resources are locked.
        pat: Personal Access Token, as accepted by `create_quelware_client()`.

    Returns:
        A configured, not-yet-started `QuelwareClient`.

    Raises:
        ValueError: If ``pat`` is neither a string, a callable, nor None.
    """
    channel = Channel(endpoint, port)
    target_unit = UnitLabel(unit_label)

    if pat is None:
        _pat = pat_provider_from_config()
    elif isinstance(pat, str):
        _pat = pat
    elif callable(pat):
        _pat = pat()
    else:
        raise ValueError(f"Unknown type for pat: {pat}")

    conf_agent = SystemConfigurationAgentMock({target_unit: UnitStatus.ACTIVE})
    session_agent = SessionAgentMock()

    def resource_agent_factory(ul: UnitLabel):
        return ResourceAgentGrpc(
            channel, metadata={"x-unit-label": str(ul), "x-pat": _pat}
        )

    def instrument_agent_factory(ul: UnitLabel):
        return InstrumentAgentGrpc(
            channel, metadata={"x-unit-label": str(ul), "x-pat": _pat}
        )

    def diagnostics_agent_factory(ul: UnitLabel):
        return DiagnosticsAgentGrpc(
            channel, metadata={"x-unit-label": str(ul), "x-pat": _pat}
        )

    def worker_agent_factory(ul: UnitLabel):
        return WorkerAgentGrpc(channel, metadata={"x-unit-label": str(ul)})

    agent_container = AgentContainer()
    agent_container.session = session_agent
    agent_container.system_configuration = conf_agent
    agent_container.trigger = TriggerAgentGrpc(channel)

    logger.warning("NOTE: Standalone client is for testing purposes.")

    return QuelwareClient(
        agent=agent_container,
        resource_agent_factory=resource_agent_factory,
        instrument_agent_factory=instrument_agent_factory,
        diagnostics_agent_factory=diagnostics_agent_factory,
        worker_agent_factory=worker_agent_factory,
        close_handlers=[channel.close],
        skip_lock_check=skip_lock_check,
    )