Skip to content

Client

RtlsClient

RtlsClient(*, username: str, password: str, base_url: str, project_uid: str | None = None, company_uid: str | None = None, timeout: float = 30.0, http_client: Client | None = None)
RtlsClient(*, token: str, base_url: str, project_uid: str | None = None, company_uid: str | None = None, timeout: float = 30.0, http_client: Client | None = None)
RtlsClient(*, username=None, password=None, token=None, base_url, project_uid=None, company_uid=None, timeout=30.0, http_client=None)

Entry point to the RTLS SDK.

Construct one client per identity. Switch project scope cheaply via :meth:with_scope (added in M8) or by passing project_uid= to the constructor.

Three construction modes are supported:

  1. From environment (recommended for production): call :meth:from_env. Reads RTLS_USERNAME / RTLS_PASSWORD / RTLS_BASE_URL (and optional scope vars) and constructs a client.
  2. Explicit credentials (for testing): pass username=, password= and base_url=.
  3. Bring-your-own token (advanced): pass token= and base_url=. The SDK cannot re-authenticate on 401 in this mode — it raises :class:AuthenticationError instead.

Examples:

>>> client = RtlsClient.from_env()
>>> tags = client.tags.list()                 # lazy login fires here
>>> client.close()                            # or use as context mgr

from_env classmethod

from_env(*, prefix='RTLS_')

Construct a client from environment variables.

Reads {prefix}USERNAME, {prefix}PASSWORD, {prefix}BASE_URL (required) plus {prefix}PROJECT_UID and {prefix}COMPANY_UID (optional). All values are looked up at call time — no caching.

Parameters:

Name Type Description Default
prefix str

Environment-variable prefix. Defaults to "RTLS_".

'RTLS_'

Raises:

Type Description
KeyError

If a required variable is missing.

with_scope

with_scope(*, project_uid=None, company_uid=None)

Return a shallow copy of this client bound to a different scope.

The copy shares the same authenticated session — _auth_state, token store, connection pool — so switching scope does not trigger a re-login. The copy resolves its scope snapshot at copy time: arguments left as None inherit the current effective scope and freeze it on the copy. Subsequent use_project / use_company calls on the original client do not affect the copy's scope.

Use this for parallel / concurrent work or any case where you need both scopes alive at once. For a long-lived in-place rebind, use :meth:use_project / :meth:use_company instead.

Examples:

>>> default_client = RtlsClient.from_env()
>>> a = default_client.with_scope(project_uid="proj-a")
>>> b = default_client.with_scope(project_uid="proj-b")
>>> a.tags.list()  # uses proj-a
>>> b.tags.list()  # uses proj-b
>>> default_client.tags.list()  # uses the env default — unchanged

use_project

use_project(project_uid)

Rebind this client's default project scope in-place.

Mutates the client. Subsequent requests use project_uid as the X-User-Project header (or omit the header when None). Unlike :meth:with_scope, this does NOT create a copy — every sub-client and every future call sees the new scope.

Not thread-safe: concurrent calls on the same client while one thread is mutating scope can interleave headers. For concurrent / parallel work use :meth:with_scope instead.

use_company

use_company(company_uid)

Rebind this client's default company scope in-place.

Same semantics as :meth:use_project — mutates in place; not thread-safe; for concurrent work use :meth:with_scope.

close

close()

Close the underlying HTTP connection pool and clear the token.

For clients returned by :meth:with_scope, close() is a no-op — the copy doesn't own the pool. Close the original client to free shared resources.

__enter__

__enter__()

__exit__

__exit__(exc_type, exc, tb)