Skip to content

Document that omit_defaults ignores custom default_factory - #1076

Merged
Siyet merged 1 commit into
mainfrom
1032-document-omit-defaults-factory
Jun 16, 2026
Merged

Document that omit_defaults ignores custom default_factory#1076
Siyet merged 1 commit into
mainfrom
1032-document-omit-defaults-factory

Conversation

@Siyet

@Siyet Siyet commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

omit_defaults only recognizes empty-collection defaults when the default is given by value or via a builtin collection constructor (list/dict/set/tuple/frozenset). A custom default_factory (a user function, lambda, or a Struct/dataclass/attrs type) is never called during detection, so its field is always encoded, even when the produced value is empty.

This is intentional: detection runs in the encode hot path and stays O(1) without invoking user code. The behavior wasn't documented though, so the matches_default section now spells out the default_factory limitation and points at default_factory=list (which type checks fine via the field annotation) as the supported way to omit an empty collection default.

Closes #1032
Closes #645

@Siyet
Siyet added this pull request to the merge queue Jun 16, 2026
Merged via the queue into main with commit e25f523 Jun 16, 2026
6 checks passed
@Siyet
Siyet deleted the 1032-document-omit-defaults-factory branch June 16, 2026 10:58
Comment thread docs/structs.rst
Comment on lines +694 to +695
still type checks. Specifying ``default=[]`` works too: ``msgspec`` doesn't
share mutable default values between instances.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This isn't true and can be misleading. It is true for builtin mutable collections, but it is not true for any mutable object.

with a list:

>>> import msgspec
>>> DEFAULT = []
>>> class A(msgspec.Struct):
...     field: list[int] = msgspec.field(default=DEFAULT)
... 
>>> print(A().field is A().field)
False

with a custom class:

>>> import msgspec
>>> from collections import UserDict
>>> class MyDict(UserDict):
...     pass
... 
>>> DEFAULT = MyDict()
>>> class A(msgspec.Struct):
...     field: dict[str, int] = msgspec.field(default=DEFAULT)
... 
>>> print(A().field is A().field)
True

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.

Default not omitted with custom default factory Allow omit_defaults to exclude fields when encoded value is {} (empty dict)

2 participants