Skip to content

Scope switching — with_scope and use_project

Two patterns for talking to a project / company other than the client's default.

with_scope — returns a copy

Snapshot the new scope into a separate client. The copy shares the authenticated session, so no re-login happens.

default = RtlsClient.from_env()

a = default.with_scope(project_uid="proj-a")
b = default.with_scope(project_uid="proj-b")

a.tags.list()           # uses proj-a
b.tags.list()           # uses proj-b
default.tags.list()     # uses the env default — unchanged

with_scope returns a separate RtlsClient instance sharing the underlying httpx.Client and _AuthState. The original isn't mutated.

Use with_scope when:

  • You need both scopes alive at the same time (e.g. parallel work).
  • You're servicing concurrent requests on different scopes.
  • You want a guarantee that the original scope is preserved.

use_project / use_company — mutates in place

client = RtlsClient.from_env()
client.use_project("proj-b")  # all subsequent calls use proj-b
client.tags.list()

use_* rebinds the client's default scope. Every sub-client and every future call sees the new scope.

Thread-safety: use_* mutates shared state. Don't call it from one thread while another thread is making requests on the same client — for concurrent work use with_scope.

Resource sharing

Both forms preserve:

  • The cached token (no re-login).
  • The HTTP connection pool.
  • The user identity (X-User-Email).

Only the scope headers (X-User-Project, X-User-Subcontractor) differ between scopes.

Cleanup

Only the original client owns the underlying pool. close() on a with_scope copy is a no-op:

default = RtlsClient.from_env()
copy = default.with_scope(project_uid="proj-b")
copy.close()           # no-op
default.close()        # frees the pool, clears the token

Closing the original after copies are still in use is a bug — copies become unusable.