Visitar URL original
Omit `dataloader_kwargs` from `TrainSettingsConfig` if unset to ensure forward compatibility by deruyter92 · Pull Request #3576 · DeepLabCut/DeepLabCut · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add model_serializer for TrainSettingsConfig.dataloader_kwargs
omit dataloader_kwargs in the .to_dict, .to_yaml and to_commented_map views when the field is not configured (empty or None)

This keeps forward compatibility in older deeplabcut versions
  • Loading branch information
deruyter92 committed Nov 3, 2026
commit eb32970154c05f732397b374bc2db1d38e33f9e4
2 changes: 2 additions & 0 deletions deeplabcut/core/config/base_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ def to_commented_map(self) -> CommentedMap:
dumped = self.to_dict(normalize=True)
data = CommentedMap()
for name, info in type(self).model_fields.items():
if name not in dumped: # excluded by a custom serializer
continue
extra = info.json_schema_extra
if isinstance(extra, dict) and (comment := extra.get("comment")):
data.yaml_set_comment_before_after_key(name, before=comment)
Expand Down
13 changes: 11 additions & 2 deletions deeplabcut/pose_estimation_pytorch/config/training.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from typing import Any

from pydantic import field_validator
from pydantic import SerializerFunctionWrapHandler, field_validator, model_serializer

from deeplabcut.core.config import DLCBaseConfig
from deeplabcut.core.config.validation import reject_reserved_keys
Expand All @@ -38,7 +38,8 @@ class TrainSettingsConfig(DLCBaseConfig):
dataloader_pin_memory: Whether to pin memory in data loader
dataloader_kwargs: Additional keyword arguments for the training
``torch.utils.data.DataLoader`` (e.g. ``persistent_workers``). Arguments
that DeepLabCut sets itself are reserved and cannot be given here.
that DeepLabCut sets itself are reserved and cannot be given here. Omitted
from the serialized config when empty.
display_iters: Display interval for training progress
epochs: Number of training epochs
seed: Random seed for reproducibility
Expand All @@ -61,3 +62,11 @@ class TrainSettingsConfig(DLCBaseConfig):
def validate_dataloader_kwargs(cls, v: dict[str, Any] | None) -> dict[str, Any] | None:
reject_reserved_keys(v, _RESERVED_DATALOADER_KWARGS, name="dataloader_kwargs")
return v

@model_serializer(mode="wrap")
def _omit_empty_dataloader_kwargs(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
# Keep configs without dataloader_kwargs loadable by older DeepLabCut versions
data = handler(self)
if not data.get("dataloader_kwargs"):
data.pop("dataloader_kwargs", None)
return data
10 changes: 10 additions & 0 deletions tests/pose_estimation_pytorch/config/test_train_settings_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,13 @@ def test_dataloader_kwargs_rejects_options_with_a_config_field(key: str, hint: s
def test_dataloader_kwargs_rejects_options_managed_by_deeplabcut(key: str) -> None:
with pytest.raises(ValidationError, match=f"dataloader_kwargs cannot include reserved options: '{key}'"):
TrainSettingsConfig.from_dict({"dataloader_kwargs": {key: False}})


@pytest.mark.parametrize("value", [None, {}])
def test_empty_dataloader_kwargs_is_omitted_when_saving(tmp_path, value) -> None:
cfg = TrainSettingsConfig(dataloader_kwargs=value)
assert "dataloader_kwargs" not in cfg.to_dict()
assert "dataloader_kwargs" not in cfg.to_commented_map()
cfg.to_yaml(tmp_path / "cfg.yaml")
assert "dataloader_kwargs" not in (tmp_path / "cfg.yaml").read_text()
assert TrainSettingsConfig.from_yaml(tmp_path / "cfg.yaml").dataloader_kwargs is None
Loading