Description
In my project, I have structs that contains list fields. I would like to omit these fields when the list is empty to reduce the size of the saved files.
When using the list constructor as the default factory or a default empty list, it works fine. However, the former conflicts with the type linter, and I want to avoid the latter (shared across all instances).
When I use a custom factory function, the field always appear in the output.
It may be the correct behavior, but I did not find any mention of this in the docs.
Reproduction
I ran this using Python 3.14 and msgspec 0.21.1.
from __future__ import annotations
import msgspec
class Fruit(msgspec.Struct):
name: str = msgspec.field(name="name")
def fruits_factory() -> list[Fruit]:
return []
class Basket(msgspec.Struct, omit_defaults=True):
size: int = msgspec.field(name="size")
material: str = msgspec.field(name="material", default="wicker")
fruits: list[Fruit] = msgspec.field(name="fruits", default_factory=fruits_factory)
class BasketWithListConstructor(msgspec.Struct, omit_defaults=True):
size: int = msgspec.field(name="size")
material: str = msgspec.field(name="material", default="wicker")
fruits: list[Fruit] = msgspec.field(name="fruits", default_factory=list) # Type error because list is untyped
class BasketWithDefaultValue(msgspec.Struct, omit_defaults=True):
size: int = msgspec.field(name="size")
material: str = msgspec.field(name="material", default="wicker")
fruits: list[Fruit] = msgspec.field(name="fruits", default=[]) # Shared mutable default value, should be avoided
if __name__ == "__main__":
basket = Basket(size=5)
print(msgspec.json.encode(basket))
# Expected output: b'{"size":5}'
# Actual output: b'{"size":5,"fruits":[]}'
basket_with_list_constructor = BasketWithListConstructor(size=5)
print(msgspec.json.encode(basket_with_list_constructor))
# Output: b'{"size":5}'
basket_with_default_value = BasketWithDefaultValue(size=5)
print(msgspec.json.encode(basket_with_default_value))
# Output: b'{"size":5}'
print(f"Using msgspec {msgspec.__version__}")
Description
In my project, I have structs that contains list fields. I would like to omit these fields when the list is empty to reduce the size of the saved files.
When using the
listconstructor as the default factory or a default empty list, it works fine. However, the former conflicts with the type linter, and I want to avoid the latter (shared across all instances).When I use a custom factory function, the field always appear in the output.
It may be the correct behavior, but I did not find any mention of this in the docs.
Reproduction
I ran this using Python 3.14 and msgspec 0.21.1.