Discovering what exists
Before you can filter on an attribute or fetch a series, you have to know it exists. The list_* family
answers that — cheap metadata queries, no point data — and it is usually where an exploratory session starts.
Attribute paths
Section titled “Attribute paths”What attributes runs carry, and of what kind:
client.list_run_attribute_definitions()# [AttributeDefinition(path='config/lr', kind=AttributeKind.FLOAT),# AttributeDefinition(path='sys/tags', kind=AttributeKind.STRING_SET), ...]Narrow by scope or by pattern:
from metrana.query import AttributeFilter
client.list_run_attribute_definitions(experiment="lr-sweep")client.list_run_attribute_definitions(run="run-001")client.list_run_attribute_definitions(filter=AttributeFilter(prefix="config/"))client.list_run_attribute_definitions(filter=AttributeFilter(regex=r"^config/.*_rate$"))# Run-level attributes across the whole project, of these two kinds only:client.list_run_attribute_definitions(filter=AttributeFilter(kinds=["float", "int"]))The same shape covers the other two resources that carry attributes:
client.list_project_attribute_definitions() # paths valid in a PROJECT filterclient.list_rl_env_attribute_definitions("rl-001") # paths valid in an ENVIRONMENT filterclient.list_rl_env_attribute_definitions("rl-001", environment="envA")Comparing several RL runs — say, one aggregation chart per run over a shared set of filters — needs the paths valid in any of them. The across-runs variant takes a list of runs (up to 100) and returns the deduplicated union over all their environments:
client.list_rl_env_attribute_definitions_across_runs(["rl-001", "rl-002", "rl-003"])There is no environment parameter here on purpose: environment ids are not comparable across runs. Scope
to environments with the single-run method instead.
kind tells you which operators are meaningful — CONTAINS ALL is a string-set thing, and < on a string
orders lexicographically rather than numerically — so listing definitions is how you build a valid filter
rather than guessing one.
Getting attribute values (not definitions)
Section titled “Getting attribute values (not definitions)”The definition listings tell you what can exist. To read one resource’s actual values:
client.list_run_attributes("run-001")client.list_rl_env_attributes("rl-001", "envA")Both return a plain dict[str, object] with Python-typed values — str, int, float, bool,
list[str] for string sets, datetime for timestamps.
Metrics
Section titled “Metrics”A metric is a name plus a scale, and the label keys its series are split by:
client.list_metric_definitions()# [MetricDefinition(metric_name='loss', scale='ML_STEP', label_keys=('worker',),# value_kind=SeriesValueKind.FLOAT), ...]
client.list_metric_definitions(prefixes=["train/"], scales=["ML_STEP"])client.list_metric_definitions(regex=r"^grad_", value_kinds=["histogram"])client.list_metric_definitions(runs=["run-001", "run-002"])value_kind is what tells you whether to reach for
fetch_float_series,
fetch_histogram_series, or
fetch_scatter_series.
Inside an RL run, the environments have their own metrics:
client.list_rl_env_metric_definitions("rl-001")client.list_rl_env_metric_definitions("rl-001", environments=["envA", "envB"])As with attributes, the across-runs variant unions the environment metrics of several runs (up to 100, no
environment scoping), and takes the same prefixes / regex / scales narrowing:
client.list_rl_env_metric_definitions_across_runs(["rl-001", "rl-002"])client.list_rl_env_metric_definitions_across_runs(["rl-001", "rl-002"], prefixes=["train/"])Series
Section titled “Series”A series is a metric with its label values pinned — the actual thing points are stored against. A metric
logged without labels has exactly one series, and the two listings coincide; they diverge only once series
were logged with labels. Where a metric definition says “loss, split by worker”, a series definition says
“loss where worker=w0”:
client.list_series_definitions(run="run-001")# [SeriesDefinition(metric_name='loss', scale='ML_STEP', key='loss(worker=w0)',# value_kind=SeriesValueKind.FLOAT, labels={'worker': 'w0'}), ...]
client.list_series_definitions(series=SeriesQuery("loss").with_label_matches("worker", "^w"))key is the column name fetch_float_series produces for that series, so a discovery result maps straight
onto a fetched frame — no string assembly on your side. Default parts are omitted: a plain metrana.log
metric’s key is just its name (loss, not loss(scale=ML_STEP)), so frame["loss"] works the way you would
guess.
Series label values
Section titled “Series label values”If your series were logged with labels, you often want just the values one key takes before building a filter. (Not using labels? Skip this — an unlabelled metric has nothing to list here.)
client.list_series_label_values("run-001", "worker")# {'worker': ['w0', 'w1', 'w2', 'w3']}
client.list_series_label_values("run-001", ["worker", "policy"])LabelKeyFilter narrows the values rather than the keys — useful when a key has thousands:
from metrana.query import LabelKeyFilter
client.list_series_label_values("run-001", LabelKeyFilter("worker", prefix="w1"))