Skip to content

🐛 Do not require the children of an omitted optional namespace - #802

Open
elinscott wants to merge 1 commit into
aiidateam:mainfrom
elinscott:upstream-optional-namespace
Open

🐛 Do not require the children of an omitted optional namespace#802
elinscott wants to merge 1 commit into
aiidateam:mainfrom
elinscott:upstream-optional-namespace

Conversation

@elinscott

Copy link
Copy Markdown
Collaborator

Problem

An optional namespace input cannot be omitted. If a task declares a grouped input that may be left out entirely — a TypedDict | None parameter, for instance — check_before_run() wrongly reports every one of that namespace's children as a missing required input:

class Window(TypedDict):
    """An energy window: both bounds, or neither."""

    lower: float
    upper: float


@task
def count_states(energies: list, window: Window | None = None) -> int:
    """Count the energies, optionally restricted to a window."""
    if window is None:
        return len(energies)
    return len([e for e in energies if window['lower'] <= e <= window['upper']])


wg = WorkGraph('example')
wg.add_task(count_states, name='count_states', energies=[-1.0, 0.5, 2.0])
wg.run()

window has a None default and the function handles its absence, but the graph will not run:

ValueError: Missing required inputs:
  • count_states.window.lower
  • count_states.window.upper

The namespace socket itself is correctly marked required = False; only its children are required. find_missing_inputs recurses into the children without consulting the parent, so their requiredness is read as absolute rather than conditional on the namespace being supplied at all.

Changes

  • An optional namespace nobody filled in is not missing anything: in this instance skip the recursion.
  • Add WorkGraph.is_socket_provided, which performs this "anything in the subtree" test (doing so recursively to catch namespaces whose child is linked from an upstream task).
  • A namespace that is partially supplied still reports its missing children, and a required namespace is unaffected.

Testing

tests/test_validation.py covers four cases:

  • An optional namespace left entirely empty reports nothing. This is the desired fix, and fails without the change.
  • An optional namespace with one of two children supplied still reports the other.
  • An optional namespace with one child linked from an upstream task output likewise still reports the unlinked child.
  • A required namespace left empty still reports both children, i.e. existing behaviour is untouched.

Reverting the source change leaves the last three passing but fails the first.

An optional namespace input left entirely unfilled reported every one
of its children as a missing required input, so a grouped optional
input (a `TypedDict | None`, for instance) could not be omitted:
`check_before_run` raised for every graph that did not supply it.

- Skip the recursion into a namespace that is not itself required and
  carries no value and no link anywhere in its subtree.
- Keep reporting the missing children of a namespace that is
  partially supplied, and of one that is required.
- Cover the empty-optional, partially-filled, linked-child and
  empty-required cases in `tests/test_validation.py`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@elinscott
elinscott force-pushed the upstream-optional-namespace branch from 3beca8e to e108276 Compare July 31, 2026 10:12
elinscott added a commit to elinscott/aiida-workgraph that referenced this pull request Aug 14, 2026
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.

1 participant