Upgrade from 2.3 to 2.4
OmegaConf 2.4 is a prerelease with breaking changes. Check the affected APIs and config inputs below before upgrading from 2.3.
Breaking changes
Python 3.6–3.9 are no longer supported
Upgrade application, CI, and deployment environments to Python 3.10 or newer before installing 2.4.
Tuple inputs no longer become mutable lists
Native tuples create structurally immutable TupleConfig values instead
of ListConfig values. Element assignment, insertion, and removal fail;
OmegaConf.is_list() returns False, and OmegaConf.to_container() returns
a tuple rather than a list for tuple input.
Pass a list when mutation is required. Use OmegaConf.is_sequence() for
code that accepts either a list or a tuple.
Tuple migration examples and type checks
For a mutable sequence, use a list. For a tuple, replace the whole value through its mutable parent:
>>> from omegaconf import OmegaConf
>>> # Use a list for mutation.
>>> cfg = OmegaConf.create({"coords": [1, 2]})
>>> cfg.coords.append(3)
>>> list(cfg.coords)
[1, 2, 3]
>>> cfg = OmegaConf.create({"coords": (1, 2)})
>>> # Replace the whole tuple.
>>> cfg.coords = (1, 2, 3)
>>> tuple(cfg.coords)
(1, 2, 3)
In structured configs, use list[T] for mutable sequences and a tuple
annotation for tuples. A fixed annotation such as tuple[int, int]
requires two elements; tuple[int, ...] accepts any number of integers.
Nested mutable containers inside a tuple remain mutable.
Use OmegaConf.is_tuple() for tuple-specific code
or OmegaConf.is_sequence() when either sequence type is accepted,
including checks that previously used isinstance(value, ListConfig) for
general sequence handling. Tuple semantics are experimental in 2.4.
Config containers cannot be dictionary keys or set elements
DictConfig and ListConfig are unhashable in 2.4. Calling hash(cfg),
using a config as a dictionary key, or adding one to a set raises
TypeError, including for read-only configs.
Use an explicit immutable key derived from the fields your application needs to identify a config.
OmegaConf.create(None) returns None
In 2.3, this call returned a DictConfig wrapping None. In 2.4, it
returns literal None. Handle None before calling container methods.
If you intended to create an empty dictionary config, pass {} explicitly.
OmegaConf.get_type() reports NoneType for null nodes
For a config node containing None, OmegaConf.get_type() now returns
type(None). Update code that branches on the previous type result. To
check whether a field's value is null, read the field and use is None.
Resolving an interpolation to a missing value raises
OmegaConf.resolve() raises InterpolationToMissingValueError when an
interpolation targets ???. In 2.3, it replaced the interpolation with
the missing marker.
Populate the referenced value before calling resolve(), or defer
resolution until the required values are available.
A resolver returning ??? produces a missing value
A resolver that returns plain "???" now makes its result missing on
access. Return r"\???" when you intend those characters as literal text.
See missing values for escaping in Python and
YAML and for checking detached values.
Typed interpolations validate on access
Interpolations into typed containers and union fields now validate and
convert their results against the destination type during lazy access.
Code that previously read an incompatible value may now raise
InterpolationValidationError; compatible container elements may be
converted to the destination's declared types.
Check the source values and destination annotations. See validation and conversion.
Resolver evaluation during export runs fewer times
OmegaConf.to_container(..., resolve=True) evaluates each custom resolver
node at most once per conversion pass, including when several
interpolations reference that node. Code that depends on repeated resolver
side effects or different results from those references must be updated.
Move required side effects out of resolvers and make distinct evaluations
explicit.
Key paths interpret backslashes before delimiters as escapes
In select(), update(), from_dotlist(), and from_cli(), a backslash
before ., [, ], or = now escapes that character. For example,
r"a\.b" addresses the single key "a.b"; it no longer navigates through
a key ending in a backslash to a nested key "b".
For nested access through a key ending in a backslash, use direct item
access or rename the key. Doubling the backslash does not restore the old
path behavior. See key paths.
Configs containing both an integer key and its string spelling, such as
1 and "1", are also rejected. Rename or normalize conflicting keys.
YAML loading enforces alias expansion limits
YAML that exceeds the expansion limits is rejected. Simplify excessive
anchors, aliases, or merge keys. For trusted input that needs a larger
limit, set max_yaml_expanded_nodes on OmegaConf.load() or
OmegaConf.create(). See YAML alias limits
for the limits and environment override.
New warnings and deprecations
- Implicit conversion: direct assignment and typed-container mutation
emit
FutureWarningwhen they convert a value to another type. This can fail applications or tests that treat warnings as errors. Assign the declared type directly or useOmegaConf.update()for explicit conversion. - Resolver annotations: argument and return annotation mismatches emit
UserWarningby default. Correct the annotations or values, or choose an explicitannotation_validationpolicy when registering the resolver. See resolver annotation validation. - Resolver registration:
register_new_resolver()andlegacy_register_resolver()are deprecated. Migrate toOmegaConf.register_resolver()and review argument parsing and validation in the custom resolver guide.
See the 2.4.0rc1 release notes for the complete release history.