Skip to content

fix: add total=False to modality Parameters TypedDicts#256

Merged
Kamilbenkirane merged 1 commit intomainfrom
fix/parameters-total-false
Apr 10, 2026
Merged

fix: add total=False to modality Parameters TypedDicts#256
Kamilbenkirane merged 1 commit intomainfrom
fix/parameters-total-false

Conversation

@Kamilbenkirane
Copy link
Copy Markdown
Member

Summary

  • Add total=False to the five modality Parameters TypedDict subclasses (TextParameters, ImageParameters, VideoParameters, AudioParameters, EmbeddingsParameters) and to the modality scaffolding template.
  • Root cause per PEP 589: "The totality flag only applies to items defined in the body of the TypedDict definition. Inherited items won't be affected, and instead use totality of the TypedDict type where they were defined."
  • Every field declared in a subclass body needs its own total=False (or PEP 655 NotRequired[...] per field) — it is not inherited from the Parameters base.

Six files changed, six lines changed.

Why PEP 589 total=False and not PEP 655 NotRequired

Equivalent under the spec. Chose total=False for consistency with the existing Parameters base and because ecosystem precedent (pydantic ConfigDict, openai-python CompletionCreateParamsBase, anthropic-sdk-python MessageCreateParamsBase, google-genai, typeshed stubs) uses TypedDict, total=False for all-optional param bags consumed via Unpack[...]. Zero NotRequired hits in openai-python or anthropic-sdk-python types folders.

Impact

Downstream consumers using strict mypy (e.g. celeste-tools) were hitting 10+ Missing named argument errors per celeste.text.generate call, one per TextParameters field. This fix makes strict-mypy downstream packages type-check cleanly against celeste-ai without needing to disable call-arg.

Internally the problem was masked by [[tool.mypy.overrides]] disable_error_code = ["call-arg"] on celeste.modalities.*.client and celeste.providers.*.* in pyproject.toml. Those overrides may become tightenable in a follow-up PR now that the root cause is fixed.

Test plan

  • make lint — ruff clean
  • make format — 394 files unchanged
  • make typecheck — 331 source + 63 test files clean under strict mypy
  • make security — bandit clean (0 issues, 18940 LOC)
  • make test — 586 passed, 0 failed (after uv sync --extra gcp)
  • pre-commit hooks — all passed on commit and pre-push

Closes #255

Per PEP 589, the totality flag only applies to fields defined in the
body of the TypedDict definition — it is not inherited from the parent.
The five modality Parameters subclasses (Text, Image, Video, Audio,
Embeddings) inherited from `class Parameters(TypedDict, total=False)`
but redeclared their own fields without the flag, so every field on
them was treated as required by mypy.

Under PEP 692 `Unpack[...]` this cascaded to downstream consumers: any
strict-mypy caller of `celeste.text.generate` (etc.) was forced to pass
all ~13 TextParameters keys. Internally silenced by
`[[tool.mypy.overrides]] disable_error_code = ["call-arg"]` on the
client modules, but leaked to downstream packages like celeste-tools.

Also fix the scaffolding template that produced this pattern.

Closes #255
@Kamilbenkirane Kamilbenkirane merged commit 11e39b3 into main Apr 10, 2026
11 checks passed
@claude
Copy link
Copy Markdown

claude bot commented Apr 10, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Kamilbenkirane added a commit that referenced this pull request Apr 10, 2026
…rrides

After #256 fixed total=False on the modality Parameters TypedDicts, the
call-arg exclusion in the big internal [[tool.mypy.overrides]] block
(modalities.*.client / streaming / providers, providers.*, namespaces.domains)
is no longer needed for the Unpack[*Parameters] pattern that originally
required it.

Removing it surfaced one previously-hidden real bug:
GoogleImagesClient.model_post_init() forgot to forward self.base_url
to the strategy client constructor (Gemini/Imagen). The wrapper would
honor a custom base_url, but the strategy would silently default to None.
Pass base_url=self.base_url at the call site.

Also tightens the override surface: 6 disabled error codes instead of 7
on the same module list. The remaining codes (override, return-value,
arg-type, assignment, no-any-return, attr-defined) cover the
provider-mixin / multiple-inheritance typing patterns and are unrelated
to #256.

The tests.* override keeps call-arg disabled — 39 test files still
construct provider clients without explicit base_url= and this PR
intentionally leaves test ergonomics alone.

Closes #257
Kamilbenkirane added a commit that referenced this pull request Apr 10, 2026
…rrides (#258)

After #256 fixed total=False on the modality Parameters TypedDicts, the
call-arg exclusion in the big internal [[tool.mypy.overrides]] block
(modalities.*.client / streaming / providers, providers.*, namespaces.domains)
is no longer needed for the Unpack[*Parameters] pattern that originally
required it.

Removing it surfaced one previously-hidden real bug:
GoogleImagesClient.model_post_init() forgot to forward self.base_url
to the strategy client constructor (Gemini/Imagen). The wrapper would
honor a custom base_url, but the strategy would silently default to None.
Pass base_url=self.base_url at the call site.

Also tightens the override surface: 6 disabled error codes instead of 7
on the same module list. The remaining codes (override, return-value,
arg-type, assignment, no-any-return, attr-defined) cover the
provider-mixin / multiple-inheritance typing patterns and are unrelated
to #256.

The tests.* override keeps call-arg disabled — 39 test files still
construct provider clients without explicit base_url= and this PR
intentionally leaves test ergonomics alone.

Closes #257
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.

Parameters TypedDict subclasses missing total=False — every field becomes required under strict mypy

1 participant