Samples
Named datasets (items, CSV, JSON) loaded at startup and accessible in Jinja2 templates.
Named datasets loaded once at startup and accessible in templates via samples.<name>. Three sample types are available:
items
Inline list of values:
| Parameter | Type | Constraints | Description |
|---|---|---|---|
type | string | Must be "items". | Sample type discriminator. |
source | list | At least one item. | Inline list of values. |
samples:
status_codes:
type: items
source: [200, 201, 301, 404, 500]csv
Load from a CSV file:
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
type | string | — | Must be "csv". | Sample type discriminator. |
source | path | — | Must end with .csv. | Path to the CSV file. |
header | boolean | false | — | Whether the first row is a header. |
delimiter | string | "," | Non-empty. | Column delimiter. |
quotechar | string | '"' | Single character. | Character used to quote fields containing the delimiter or newlines (RFC 4180). |
samples:
users:
type: csv
source: samples/users.csv
header: truejson
Load from a JSON file (array of objects with consistent keys):
| Parameter | Type | Constraints | Description |
|---|---|---|---|
type | string | Must be "json". | Sample type discriminator. |
source | path | Must end with .json. | Path to the JSON file. |
samples:
endpoints:
type: json
source: samples/endpoints.jsonAll objects in a JSON sample must have the same set of keys. If keys differ between objects, the sample will fail to load with an error.
Accessing sample rows
Each row in a sample is a tuple-like object. You can pick a random row and access its fields:
{%- set user = samples.users | random -%}Named access — CSV samples with header: true and JSON samples expose fields by name, matching CSV column headers or JSON object keys:
{%- set user = samples.users | random -%}
{{ user.name }} {# "John" #}
{{ user.email }} {# "john@example.com" #}Index access — all sample types (including items and CSV without headers) support positional index access:
{{ user[0] }} {# first field #}
{{ user[1] }} {# second field #}Both access styles work on the same row — named access is available whenever headers or keys are present, index access always works.
Picking sample rows
Each sample provides methods for random row selection — both uniform and weighted.
Uniform picking
Use pick() to select a single random row, or pick_n(n) to select multiple:
{%- set user = samples.users.pick() -%}
{{ user.name }}
{%- set five_users = samples.users.pick_n(5) -%}
{%- for u in five_users -%}
{{ u.name }}
{%- endfor -%}| Method | Signature | Description |
|---|---|---|
pick | (default: Any = ...) → Row | Pick a single random row (uniform distribution). |
pick_n | (n: int) → list[Row] | Pick n random rows with replacement. |
pick() is equivalent to | random but is also available as a method for consistency with the weighted API below.
Pass default to pick() to handle empty samples (for example after where() filtering): samples.users.where(role="admin").pick(default=None). Without default, picking from an empty sample raises an error. pick_n returns an empty list on empty samples - no default needed.
Weighted picking
If your sample includes a numeric column for weights, you can pick rows with probability proportional to those weights:
name,port,protocol,weight
HTTP,80,tcp,50
HTTPS,443,tcp,30
SSH,22,tcp,10
DNS,53,udp,10{%- set service = samples.services.weighted_pick('weight') -%}
{{ service.name }}:{{ service.port }}
{%- set batch = samples.services.weighted_pick_n('weight', 10) -%}| Method | Signature | Description |
|---|---|---|
weighted_pick | (weight: str, default: Any = ...) → Row | Pick a single random row with probability proportional to the named weight column. |
weighted_pick_n | (weight: str, n: int) → list[Row] | Pick n random rows with replacement, weighted by the named column. |
The weight column must contain numeric values (integers or floats). Negative values and all-zero weights will produce an error. The weight column remains part of the returned row — you can simply ignore it in your template.
weighted_pick accepts the same default parameter as pick to handle empty samples. weighted_pick_n returns an empty list on empty samples.
Weights are extracted and cached on the first call. Repeated calls to weighted_pick with the same column are efficient even at high throughput.
Filtering rows
Use where(**conditions) to filter a sample by one or more equality conditions, then pick from the result:
{%- set admin = samples.users.where(role="admin").pick() -%}
{{ admin.name }}Conditions are AND-combined. The example below picks a server in the servers subnet:
{%- set host = samples.internal_hosts.where(role="server", subnet="servers").pick() -%}where() returns a new sample, so all picking methods - pick, pick_n, weighted_pick, weighted_pick_n - chain naturally. Calls can also be chained:
{%- set host = samples.internal_hosts.where(role="server").where(subnet="servers").pick() -%}If no row matches, the filtered sample is empty. Use pick(default=...) to handle that case without an error:
{%- set maybe_host = samples.internal_hosts.where(role="server").pick(default=None) -%}
{%- if maybe_host -%}
{{ maybe_host.address }}
{%- else -%}
(no server)
{%- endif -%}| Method | Signature | Description |
|---|---|---|
where | (**conditions: Any) → Sample | Return a new sample of rows matching all equality conditions. |
For non-equality predicates (substring match, ranges, etc.), use Jinja2's selectattr filter: samples.users | selectattr("name", "search", "^a") | list. where() covers the common equality case.