Install
openclaw skills install @loonghao/rez-python-apiRez Python API — ResolvedContext construction and inspection, Package/Variant objects, programmatic resolves, .rxt context serialisation and deserialisation, running commands inside a context, and the module entry points (rez.resolved_context, rez.packages, rez.config, rez.pip, rez.suite, rez.bundle_context). Use when the user wants to drive rez from Python instead of the CLI, or asks what a context object actually holds. Covers Rez 3.4.0.
openclaw skills install @loonghao/rez-python-apiOne-sentence summary:
ResolvedContextis the whole product — build one from a list of request strings, read the result offsuccess,resolved_packagesandget_environ(), persist it withsave()/load(), and only open a shell throughexecute_shell()when you really need one.
Skill scope: embedding rez in Python. For the CLI equivalents see rez-cli; for solver internals see
rez-resolve; for a context used as a deliverable artifact see rez-suites-bundles.
Two warnings straight from upstream docs/source/api.rst, and both change the design of a tool:
REZ_VERSION.REZ_CONFIG_FILE afterwards. A tool that has to change config mid-run must
shell out to the CLI instead.Confirm what you are actually about to import before you trust any of the code below:
rez-status
| Module | What it holds |
|---|---|
rez.resolved_context | ResolvedContext — a resolve, and everything you do with one |
rez.packages | Package, Variant, iter_packages, get_package, get_variant, get_latest_package_from_string |
rez.config | config — the merged, live settings object |
rez.resolver, rez.solver | Resolver, ResolverStatus, the solver itself |
rez.suite | Suite — see rez-suites-bundles |
rez.bundle_context | bundle_context — see rez-suites-bundles |
rez.pip | pip_install_package — see rez-pip-integration |
rez.developer_package | build a package from source in-process |
rez.package_repository, rez.package_resources | repositories and the resources they hand out |
rez.version | Version, VersionRange, Requirement, RequirementList, VersionError |
rez.exceptions | every rez error type; all of them derive from RezError |
rez.wrapper | the module behind the main console script |
from rez.resolved_context import ResolvedContext
# Requests are plain strings, exactly what you would pass to rez-env.
context = ResolvedContext(["foo-1", "bar"])
if not context.success:
raise SystemExit(context.failure_description)
ResolvedContext(requests, ...) takes the request list positionally. The arguments worth knowing:
| Argument | Meaning |
|---|---|
verbosity | 0, 1 or 2 — the same levels rez-env -v gives you |
timestamp | epoch time; ignore packages released after it |
building / testing | resolve as if for rez-build / rez-test |
caching | None defers to the resolve_caching setting; False bypasses caches |
package_paths | override packages_path for this resolve only |
package_filter | a PackageFilterList; rez.package_filter.no_filter removes filtering |
add_implicit_packages | append the implicit_packages (default True) |
max_fails / time_limit | stop after N failures / after N seconds |
Set verbosity=1 before reaching for a debugger: the solver trace is the same one rez-env -v
prints.
context.status # ResolverStatus.solved | .failed | .aborted | .pending
context.success # True when status is solved
context.failure_description # why it failed, when it did
context.requested_packages() # [Requirement, ...] — the request; implicits only if include_implicit=True
context.resolved_packages # [Variant, ...] — what the solver picked
context.resolved_ephemerals # resolved ephemeral (implicit-ish) packages
context.get_resolve_as_exact_requests() # ['foo==1.1.0', ...] — pin the resolve down
context.get_environ() # dict: the environment the context would produce
context.get_tools() # {tool_name: (Variant, [alias, ...])}
context.which("foo") # absolute path to a tool, or None
context.get_resolved_package("foo") # the Variant, or None
context.print_info(source_order=True) # the rez-context --so view, on stdout
resolved_packages yields Variant objects, not Package objects. A Package is a family; a
Variant is one resolved member of it, with .name, .version, .qualified_name, .root,
.requires, .tools and .data on it. Reach for get_resolved_package(name) when you want one
package out of a resolve, and get_environ() when you want the environment without running
anything.
.rxt)A context serialises to a .rxt file, which is how a resolve becomes something you can hand to
another process, another machine, or another day:
context.save("context.rxt") # write it
same = ResolvedContext.load("context.rxt") # read it back
# Or keep it in memory:
from io import StringIO
buf = StringIO()
context.write_to_buffer(buf)
buf.seek(0)
again = ResolvedContext.read_from_buffer(buf)
# Or move it through your own dict/JSON pipeline:
data = context.to_dict()
rebuilt = ResolvedContext.from_dict(data)
save() / load() and write_to_buffer() / read_from_buffer() round-trip the resolve, not the
environment — loading is cheap, and no package payload is re-read. to_dict() carries the metadata
(status, package_requests, resolved_packages, failure_description, serialize_version,
rez_version, ...) rather than a stable public schema; treat it as rez's own format, not as an API
you own.
validate() re-checks the context and raises ResolvedContextError when it no longer holds; call
it before trusting a context that has been sitting on disk.
# One command, non-interactive, with the context's environment:
proc = context.execute_command(["foo", "--version"])
print(proc.returncode)
# The environment as shell source, without starting a shell:
code = context.get_shell_code()
# An interactive shell — blocks, so only do this in a real terminal:
context.execute_shell(block=True)
Prefer execute_command() and get_environ() in automation. execute_shell() inherits the
terminal, so it is the wrong call in a service or a test; get_shell_code() takes a style of
OutputStyle.file (writable into a script) or OutputStyle.eval (sourceable in one shot).
from rez.packages import iter_packages, get_package, get_latest_package_from_string
for package in iter_packages("foo"): # every version of one family
print(package.version)
package = get_package("foo", "1.1.0") # one exact package, or None
latest = get_latest_package_from_string("foo")
get_latest_package_from_string accepts the same spellings a request does, so it is also the
cheapest way to turn a user-supplied string into a concrete package. iter_packages walks the
search path; both take paths= when you need to point them at a specific repository.
from rez.config import config
config.packages_path
config.local_packages_path
config is the merged settings object, so an attribute read is the answer to "what took effect",
not "what is in the file". It is read at import — see the warning at the top.
Every rez exception derives from RezError (rez.exceptions), so one except RezError catches
the library. The ones you are most likely to handle:
| Exception | Raised by |
|---|---|
ResolveError | a resolve that cannot be performed |
PackageNotFoundError / PackageFamilyNotFoundError | a package that is not there |
PackageRequestError | a malformed request string |
ResolvedContextError | validate() on a context that no longer holds |
SuiteError | suite operations — see rez-suites-bundles |
ContextBundleError | bundling — see rez-suites-bundles |
When an API result looks wrong, reproduce it with the CLI before you debug your own code — the CLI is the reference implementation and it reads the config fresh:
rez-env foo -o context.rxt --no-cache # ResolvedContext(..., caching=False)
rez-context context.rxt --so # context.print_info(source_order=True)
rez-context --so prints exactly the requested packages / resolved packages split that
context.print_info(source_order=True) prints, and -v on rez-env is the same trace you get from
verbosity=1.
| Symptom | Cause |
|---|---|
| Config changes ignored | rez was already imported; the API cannot reread config. Use the CLI |
resolved_packages order surprises you | it is solver order; only print_info() sorts, and source_order=True skips that sort |
| Attribute missing after an upgrade | no cross-version API guarantees — pin rez |
A resolve differs from rez-env | compare package_paths, add_implicit_packages and caching |
execute_shell() hangs in CI | it wants a terminal; use execute_command() |
ResolvedContext, then read success and failure_description before anything else.resolved_packages / get_environ() / get_tools() instead of opening a shell.save() when another process needs the resolve; validate() it before trusting it.