Skip to content

🐛 Derive socket requiredness from a model field's default - #173

Open
elinscott wants to merge 2 commits into
scinode:mainfrom
elinscott:fix/model-default-requiredness
Open

elinscott wants to merge 2 commits into
scinode:mainfrom
elinscott:fix/model-default-requiredness

Conversation

@elinscott

Copy link
Copy Markdown
Collaborator

Summary

A task taking a dataclass or a pydantic model as input refused to run unless the caller filled in every field, defaults included. Given

@dataclass
class Base:
    nelec: int
    tot_magnetization: Optional[int] = None
    ecut: float = 40.0

@task
def consume(settings: Base) -> int:
    return settings.nelec

a caller who set only nelec was told settings.tot_magnetization was missing, and ecut escaped the same complaint only because its default is not None. SocketSpecAPI.from_model copied each field's default onto the child spec but never derived requiredness from it, so meta.required kept its True default. The function-signature path and the TypedDict path already derive requiredness; the model paths now do too.

Changes

  • Mark a model field's socket optional when the field declares a default, in all four branches of from_model
  • Treat a default_factory as a default
  • Apply requiredness to namespace fields as well, though defaults are still set only on leaves. A field like sub: Optional[Sub] = None may be omitted like any other; a namespace simply has no place to keep the default value, and its requiredness is the only thing that says the caller may skip it.
  • The flag is set to False rather than left as None. If we left as None, merge_meta lets a True base survive it, and SocketMeta.to_dict omits it so from_dict restores the True default. Only False states optionality in a way that survives a round trip

Not covered

Three other paths still set a leaf default without touching requiredness: namespace(b=(int, 5)), set_default, and the mapping default of a namespace parameter. They are outside from_model and therefore outside this fix; a downstream consumer that exempts defaulted sockets from its own missing-input check still needs that exemption for them.

Closes #172

elinscott and others added 2 commits August 14, 2026 09:52
A dataclass or pydantic field with a default reached the caller as a
required socket, so a graph that left it alone failed with a missing
required input naming that field.

- Mark a field optional when it declares a default or a default factory,
  in the pydantic, dataclass, and dynamic branches of `from_model`.
- Read the factory's presence only, never calling it, so a field's
  default value is still copied only from a plain default.
- Apply requiredness to namespace fields too, which carry no default
  value but may be omitted just the same.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three of the new tests asserted the same thing twice in one function,
once for a dataclass and once for a pydantic model, so a failure did not
say which kind broke.

- Parametrize them over the two model kinds, with `dataclass` and
  `pydantic` ids.
- Build the default-factory models from a per-case factory, so each case
  asserts its own factory went uncalled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.70115% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.77%. Comparing base (8d85e61) to head (2437e1e).

Files with missing lines Patch % Lines
tests/test_socket_spec.py 97.18% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #173      +/-   ##
==========================================
+ Coverage   89.68%   89.77%   +0.09%     
==========================================
  Files          81       81              
  Lines        8984     9069      +85     
==========================================
+ Hits         8057     8142      +85     
  Misses        927      927              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@elinscott elinscott changed the title Derive socket requiredness from a model field's default 🐛 Derive socket requiredness from a model field's default 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.

A model field with a default still yields a required socket

1 participant