Skip to content

Fix json schema defaults for set / bytearray default_factory fields - #1183

Merged
Siyet merged 8 commits into
msgspec:mainfrom
vmphase:fix/json-schema-default-factory
Sep 28, 2026
Merged

Siyet merged 8 commits into
msgspec:mainfrom
vmphase:fix/json-schema-default-factory

Conversation

@vmphase

@vmphase vmphase commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #1182
Now values are json-serializable: [] / "" instead of raw set() / bytearray().

@vmphase vmphase changed the title fix: convert set / bytearray factory defaults through to_builtins Fix json schema defaults for set / bytearray default_factory fields Sep 15, 2026

@Siyet Siyet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix. The change looks right to me.

Two things before this can be merged.

The format check fails on the new line, so CI is red and the test jobs were skipped entirely. Pls run just hooks and push the reformatted version.

The change also needs a regression test. There is currently no coverage for set or bytearray factory defaults in tests/unit/test_schema.py, so a future regression would go unnoticed. A test parametrized over list, dict, set and bytearray asserting the emitted default and calling json.dumps on the resulting schema would cover it, with list and dict as controls.

@vmphase
vmphase requested a review from Siyet September 18, 2026 09:52
@vmphase

vmphase commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the quick fix. The change looks right to me.

Two things before this can be merged.

The format check fails on the new line, so CI is red and the test jobs were skipped entirely. Pls run just hooks and push the reformatted version.

The change also needs a regression test. There is currently no coverage for set or bytearray factory defaults in tests/unit/test_schema.py, so a future regression would go unnoticed. A test parametrized over list, dict, set and bytearray asserting the emitted default and calling json.dumps on the resulting schema would cover it, with list and dict as controls.

Hello. Thanks for the review, addressed both changes in the two commits above.

@Siyet Siyet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx for the fix. Both points are addressed.

Worth noting the fix covers more than the test shows: a bare tags: set[str] = set() becomes factory internally, so it produced the same unusable value before this change.

@vmphase

vmphase commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Thx for the fix. Both points are addressed.

Worth noting the fix covers more than the test shows: a bare tags: set[str] = set() becomes factory internally, so it produced the same unusable value before this change.

Should I update the test to cover this edge-case as well before the PR can get merged?

@Siyet

Siyet commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

No need, the existing test already covers it. A bare tags: set[str] = set() and msgspec.field(default_factory=set) are the same thing by the time the schema code runs: both have default_factory=set and no default, so a second case would exercise the same path. My note was about how far the fix reaches in practice, not about a gap in coverage.

Good to go from my side

@vmphase

vmphase commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

No need, the existing test already covers it. A bare tags: set[str] = set() and msgspec.field(default_factory=set) are the same thing by the time the schema code runs: both have default_factory=set and no default, so a second case would exercise the same path. My note was about how far the fix reaches in practice, not about a gap in coverage.

Good to go from my side

Oh, I originally misunderstood your previous comment. I see now, thanks.

@Siyet
Siyet added this pull request to the merge queue Sep 28, 2026
Merged via the queue into msgspec:main with commit c23e150 Sep 28, 2026
24 checks passed
@vmphase
vmphase deleted the fix/json-schema-default-factory branch September 29, 2026 04:43
pull Bot pushed a commit to Future-Outlier/msgspec that referenced this pull request Sep 29, 2026
0.22.0 has not been published yet, and the PyPI trusted publisher needed
for the upload is now configured (msgspec#1134). Entries for changes merged
after 2026-08-11 are under Unreleased, and the GitHub release form is
pre-filled from the first `Version` section only
(`scripts/release_github.py`), so those entries would be left out.

This moves them into the 0.22.0 section, groups the section by kind
(features and platforms, fixes, type stubs, docs), merges the two "Many
type stub improvements and fixes" entries into one, adds an entry for
msgspec#1183 and sets the release date. No other entry text was changed.

Co-authored-by: Tseluiko Aleksandr <[email protected]>
00200200 pushed a commit to 00200200/msgspec that referenced this pull request Oct 13, 2026
…lds (msgspec#1222)

`msgspec.json.schema` sets `"default"` for a Struct field with a
`list`/`dict`/`set`/`bytearray` `default_factory` (msgspec#1183), but not for
the same field on a dataclass or attrs class:

```python
@dataclasses.dataclass
class D:
    x: list[int] = dataclasses.field(default_factory=list)

msgspec.json.schema(D)["$defs"]["D"]["properties"]["x"]
# {'type': 'array', 'items': {'type': 'integer'}}
```

This applies the Struct rule to the dataclass/attrs/TypedDict branch.
`test_dataclass_or_attrs` now expects `"default": {}` for its `dict`
factory field.

Co-authored-by: sobolevn <[email protected]>
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.

json.schema() generates non-serializable default values

2 participants