Collection items¶
Tip
Code for examples in this page can be found in examples/12_collection_items.
You can reference an individual item in a collection by its index, which lets you modify its value.
From the command line¶
Individual items of a collection are referenced using their positional index in their path.
For example, returning to the examples introduced in Tutorial #11, we can modify the first item of the input using the --input.0 flag.
Note that types specified as tuple are not immutable during the configuration build-up: here, the tuple initialized by the configuration file is modified from the command line.
Negative indices also work, allowing to index counting from the end of the sequence. For example, here we modify the last element of the input:
Indices work at any level of the key path, not just for the leaf type.
$ # A collection of database configurations
$ uv run myapp.py --config config.yaml
Config(dbs=[SQLiteConfigChild(dbpath='db.sqlite'),
PostgreSQLConfigChild(host='example.com',
port=5432,
schema_name='mydb')])
$ # Change the schema_name of the last configuration
$ uv run myapp.py --config config.yaml --dbs.-1.schema_name other_db
Config(dbs=[SQLiteConfigChild(dbpath='db.sqlite'),
PostgreSQLConfigChild(host='example.com',
port=5432,
schema_name='other_db')])
Indices compose at every level of nesting. When an item is itself a collection, a deeper index patches that inner item in place rather than replacing the whole inner collection.
$ uv run list_of_list_of_ints.py --config list_of_list_of_ints.yaml
Config(input=[[1, 2, 3], [4, 5]])
$ # Let's modify the first element of the last list
$ uv run list_of_list_of_ints.py --config list_of_list_of_ints.yaml --input.-1.0 42
Config(input=[[1, 2, 3], [42, 5]])
From environment variables¶
From configuration files¶
Indexing also works from within configuration files. The same behavior as above is obtained with this configuration file:
$ uv run myapp.py --config config.yaml partial_config.yaml
Config(dbs=[SQLiteConfigChild(dbpath='db.sqlite'),
PostgreSQLConfigChild(host='example.com',
port=5432,
schema_name='other_db')])
And finally, indexing also works for partial configuration files. The same behavior can be obtained with a partial PostgreSQL configuration containing only the schema name:
This partial PostgreSQL configuration is then used to update the existing configuration by loading it at the end of the dbs collection:
$ uv run myapp.py --config config.yaml --config.dbs.-1 schema_name.yaml
Config(dbs=[SQLiteConfigChild(dbpath='db.sqlite'),
PostgreSQLConfigChild(host='example.com',
port=5432,
schema_name='other_db')])
Building a collection from its elements¶
A collection can be built element by element, in any order.
Its fixed length is known from the type, so negative indices count from the end here too.
$ uv run pair_of_ints.py --input.0 42 --input.1 -0xF
Config(input=(42, -15))
$ uv run list_of_ints.py --input.1 42 --input.0 -0xF
Config(input=[-15, 42])
In the case of a tuple, negative indices work because its length is known. This is not the case for lists.
$ uv run pair_of_ints.py --input.0 42 --input.-1 -0xF
Config(input=(42, -15))
$ uv run list_of_ints.py --input.0 42 --input.-1 -0xF # Error
...
Note that this behavior is for building a collection that does not yet exist. When the collection already exists, the behavior is different for lists, as indices can only modify existing elements.
$ uv run list_of_ints.py --config pair_of_ints.yaml
Config(input=[1, 2])
$ # Error: `2` is not a valid positional index
$ uv run list_of_ints.py --config pair_of_ints.yaml --input.2 3
...
...
Tuples don't have this problem and can be constructed part by part. Because the length is known from the type, an index past the end of a shorter base completes the tuple rather than being rejected.