Skip to content

Document OmegaConf.merge handling of MISSING values (#771)#1309

Open
jbbqqf wants to merge 2 commits into
omry:mainfrom
jbbqqf:docs/771-merge-missing-note
Open

Document OmegaConf.merge handling of MISSING values (#771)#1309
jbbqqf wants to merge 2 commits into
omry:mainfrom
jbbqqf:docs/771-merge-missing-note

Conversation

@jbbqqf
Copy link
Copy Markdown

@jbbqqf jbbqqf commented May 21, 2026

Summary

OmegaConf.merge treats MISSING ("???") on the source side as "no value to apply" — a non-missing target value is never overwritten by a missing source value. This behavior has resurfaced repeatedly in user discussions (#729, hydra#1729) but was not stated in the docs. Add a short doctest-backed subsection next to the existing OmegaConf.merge() walk-through.

Fixes #771.

Context

Issue #771 (filed by @Jasha10) flagged that the merge-vs-missing rule is part of the public contract but only discoverable by reading source. The two motivating discussions:

The behavior itself is unchanged; this PR only adds documentation.

Changes

  • docs/source/usage.rst — new "Missing values in merge()" subsection under the existing OmegaConf.merge() heading. Contains a sphinx doctest exercising both orderings (merge(base, override) keeps the concrete value; merge(override, base) fills the missing one) and a one-line motivation for the behavior.
  • news/771.docs — towncrier entry.

Reproduce BEFORE/AFTER yourself (copy-paste)

# --- one-time setup ---
git clone https://github.com/omry/omegaconf.git /tmp/repro-771 && cd /tmp/repro-771
python -m venv .venv && . .venv/bin/activate
pip install -e . pyyaml attrs sphinx sphinx-tabs setuptools antlr4-tools antlr4-python3-runtime
python setup.py antlr

# --- BEFORE (origin/main) ---
git checkout origin/main -- docs/source/usage.rst
grep -c "Missing values in \`\`merge" docs/source/usage.rst
# Expected: 0 (subsection absent).

# --- AFTER (this PR) ---
git fetch https://github.com/jbbqqf/omegaconf.git docs/771-merge-missing-note
git checkout FETCH_HEAD -- docs/source/usage.rst
grep -c "Missing values in \`\`merge" docs/source/usage.rst
# Expected: 1 (subsection present).

# Run the new doctest snippet on its own to verify it executes cleanly:
python - <<'PY'
from omegaconf import OmegaConf
base = OmegaConf.create({"port": 80})
override = OmegaConf.create({"port": "???"})
assert str(OmegaConf.merge(base, override)) == "{'port': 80}"
assert str(OmegaConf.merge(override, base)) == "{'port': 80}"
print("ok")
PY
# Expected: ok

What I ran locally

  • sphinx-build -b doctest docs/source /tmp/doctest_out on the branch: 409 tests, 18 failures + 1 setup failure.
  • sphinx-build -b doctest docs/source /tmp/doctest_main on origin/main: 404 tests, 18 failures + 1 setup failure.

The 5-test delta is exactly the size of the new doctest block (one >>> from omegaconf... plus four >>> data lines plus two expected outputs). The failure count is unchanged: my added block contributes zero new failures and the 18 pre-existing failures are numpy/repr-formatting artifacts unrelated to this PR.

  • Spot-checked the new doctest interactively:
    >>> OmegaConf.merge(base, override)   # → {'port': 80}
    >>> OmegaConf.merge(override, base)   # → {'port': 80}
    
    Both match the expected output in the rst block.

Edge cases tested

# Scenario Input Expected Verified by
1 Concrete then missing merge({port: 80}, {port: "???"}) concrete value preserved new doctest snippet
2 Missing then concrete merge({port: "???"}, {port: 80}) missing filled by concrete new doctest snippet
3 Pre-existing doctest count full sphinx doctest run 18 failures → 18 failures (no new) sphinx-build output diff above

Risk / blast radius

Documentation only. No code changed, no behavior changed. The only file in omegaconf/ is untouched; the only addition is one .rst subsection plus a towncrier entry.

Release note

Documented `OmegaConf.merge` behavior with `MISSING` values: a missing value on the source side does not overwrite a non-missing value on the target.

PR drafted with assistance from Claude Code. The doctest snippet was verified manually against origin/main (behavior is pre-existing, only the docs change). The reproducer block above was used during development; it is the same one a reviewer can paste verbatim.

jbbqqf added 2 commits May 22, 2026 01:11
`OmegaConf.merge` gives `MISSING` ("???") on the source side a "no value
to apply" semantic — a non-missing value on the target is never
overwritten by a missing value coming from a later config. This comes
up regularly in user discussions (omry#729, hydra#1729) but was not stated
in the docs.

Add a short doctest-backed subsection to `docs/source/usage.rst` next
to the `OmegaConf.merge()` walk-through showing both directions (source
MISSING is skipped; target MISSING is filled by a later concrete value)
and a one-line motivation for the behavior.
@omry
Copy link
Copy Markdown
Owner

omry commented May 22, 2026

Hi @jbbqqf, thanks again for your help.
One small general pushback:
Items that are marked as triage are items that I did yet get to evaluate and decide what to do with.
providing a fix is not necessarily the hard part, I still need to look at the problem and decide if I agree with it, and to decide on the course of action.

Filing a PR before I have an idea of how i want to solve it is premature.
When you look for candidates, maybe loot issues I have responded to and was positive about a fix. (Even this does not guarantee that I will now agree with Omry from 4 years ago, but it increases the odds).

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document special treatment of "???" by OmegaConf.merge

2 participants