Migrating tuple usage in OmegaConf 2.4¶
OmegaConf 2.4 changes how native Python tuples are represented. Earlier
versions converted tuples to mutable ListConfig objects. OmegaConf 2.4
preserves tuple identity by creating structurally immutable TupleConfig
objects instead.
Important
This is a breaking change. Code that assumes every OmegaConf sequence is a
ListConfig, or that mutates values created from Python tuples, may need
to be updated.
What changed¶
Given the following input:
cfg = OmegaConf.create({"coords": (1, 2)})
Earlier OmegaConf versions produced a ListConfig for cfg.coords and
allowed operations such as append() and item assignment. OmegaConf 2.4
produces a TupleConfig instead:
assert OmegaConf.is_tuple(cfg.coords)
assert OmegaConf.is_sequence(cfg.coords)
assert not OmegaConf.is_list(cfg.coords)
Like a native Python tuple, a TupleConfig does not allow elements to be
inserted, removed, or replaced. Nested mutable containers remain mutable.
OmegaConf.to_container() also converts a TupleConfig back to a native
tuple rather than a list.
Choosing the intended sequence type¶
If the value should be mutable, use a list explicitly:
cfg = OmegaConf.create({"coords": list(source_tuple)})
assert OmegaConf.is_list(cfg.coords)
cfg.coords.append(3)
For Structured Configs, annotate mutable sequences as list[T] or
typing.List[T].
If the value is conceptually a tuple, keep the tuple input or use a tuple
annotation. Treat the resulting TupleConfig as immutable and replace the
complete value through its mutable parent when an update is required:
cfg = OmegaConf.create({"coords": (1, 2)})
cfg.coords = (1, 2, 3)
The untyped tuple in this example has the variadic type Tuple[Any, ...],
so its replacement may have a different arity. A fixed annotation such as
tuple[int, int] requires replacements to contain exactly two elements,
while a variadic annotation such as tuple[int, ...] permits the arity to
change.
For Structured Configs, tuple[T1, T2] and typing.Tuple[T1, T2] define
fixed positional types, while tuple[T, ...] and typing.Tuple[T, ...]
define a homogeneous tuple of arbitrary length.
Checking sequence types¶
Choose the helper that matches the behavior your code requires:
Use
OmegaConf.is_tuple(value)for tuple-specific behavior.Use
OmegaConf.is_list(value)for mutable-list-specific behavior.Use
OmegaConf.is_sequence(value)when eitherListConfigorTupleConfigis accepted.
Code that previously used isinstance(value, ListConfig) or only
OmegaConf.is_list(value) for general sequence handling should normally use
OmegaConf.is_sequence(value) instead.
Migration checklist¶
When upgrading to OmegaConf 2.4, review code that:
accepts or recursively processes only
listandListConfiginputs;uses
OmegaConf.is_list()for generic indexed traversal or other sequence behavior that should also apply to tuples;constructs sequences incrementally with operations such as
append()or item assignment, which are not supported byTupleConfig; orexpects tuple-valued inputs to reach callables or tests as
ListConfigorlist. They now remainTupleConfigunless converted, and conversion produces a nativetuple.
Tuple semantics are experimental in OmegaConf 2.4. Feedback is welcome on GitHub issue #392.